Я пытаюсь построить модульный ngInclude. Под этим я подразумеваю, что ngIncluded JSP будет тянуть во всех зависимостях, которые ему нужны, и перекомпилировать себя перед рендерингом.Угловые множественные ngIncludes с заменой на страницу Losing Scope (?)
Этот же файл используется несколько раз на одной странице. На главной странице есть несколько вкладок - все они используют этот ngInclude только с некоторыми различными параметрами строки запроса. Кроме того, на каждой странице у меня есть «предварительная версия» включенного файла, а затем, когда они нажимают на предварительный просмотр, модальный всплывает, что снова ngIncludes тот же файл, но имеет другой параметр строки запроса, который помещает его в режим редактирования ,
Я получил это, чтобы работать везде, кроме IE9 (gah), и, конечно же, я должен поддерживать IE9, и мне приходится реорганизовывать все. Из-за желания сделать это ngInclude модульным и иметь его, включая все свои зависимости, каждый раз, когда это было объявлено, он снова вносил те же зависимости. Это было прекрасно в более современных браузерах, которые обрабатывали это более изящно, но в IE9 он взорвался бы multiple directives asking for template
или multiple directives asking for transclusion
. Единственные выводы, которые я мог найти, которые были применимы к моей ситуации, показали, что это связано с тем, что зависимости затягиваются в несколько раз. И с тем, что я смог до сих пор работать, я подтвердил, что это так.
Итак, вот я. Я пытаюсь выполнить эту работу, только однажды введя зависимости (с RequireJS). Я не использую маршруты. Я работаю над начальной загрузкой страницы, но как только я меняю вкладки или открываю редактирующий модал (оба действия вызывают другой ngInclude), я ничего не получаю. Я буквально получаю пустую страницу.
Я положил console.log
s и вижу, что порядок операций такой, какой он есть (попадает в мою директиву перекомпиляции, он делает все на всем протяжении $compile
, а затем удаляются внутренние директивы). Я также могу использовать консоль браузера для доступа к $('selectorForController').scope().items
или $('selectorForController').scope().params
и подтвердить, что у них есть данные, которые я ожидаю. Проблема в том, что по какой-то причине представление не обновляется (это то, что я ожидал от запуска $compile
).
App Определение:
var providers = {};
var myApp = angular.module('myApp', ['ngSanitize', 'ngAnimate', 'ngResource', 'pascalprecht.translate', 'angularFileUpload', function($controllerProvider, $compileProvider, $provide) {
providers = {
$controllerProvider : $controllerProvider,
$compileProvider : $compileProvider,
$provide : $provide
};
}]);
var queueLen = myApp._invokeQueue.length;
ngIncluded JSP:
<jsp:include page="profileIncludeListTemplate.jsp"/> <%-- Contains the profileItemList.jsp ng-template --%>
<jsp:include page="profileIncludePanelTemplate.jsp"/> <%-- Contains the profileItemPageRightPanel.jsp ng-template --%>
<script type="text/javascript">
// Define itemsData and params here
</script>
<%-- One of my iterations was trying to use a directive I called lazyscript to load in all of the dependencies and then recompile, but that didn't work --%>
<%--<lazyscript data-src="/assets/js/profile/profileItemPageService.js"></lazyscript>--%>
<%--<lazyscript data-src="/assets/js/profile/profileItemService.js"></lazyscript>--%>
<%--<lazyscript data-src="/assets/js/profile/profileIncludeController.js"></lazyscript>--%>
<%--<lazyscript data-src="/assets/js/profile/profileIncludeDirectives.js"></lazyscript>--%>
<%-- Another iteration was trying to get it to work this way, where I also wrote a directive to overload the default script tag and recompile if necessary, but that didn't work either --%>
<%--<script src="/assets/js/profile/profileItemPageService.js" type="text/javascript"></script>--%>
<%--<script src="/assets/js/profile/profileItemService.js" type="text/javascript"></script>--%>
<%--<script src="/assets/js/profile/profileIncludeDirectives.js" type="text/javascript"></script>--%>
<%--<script src="/assets/js/profile/profileIncludeController.js" type="text/javascript"></script>--%>
<%-- I can't define the ngController here because it will throw an error on initial load and stop the rest of the execution, so I have the recompile apply it --%>
<%-- So I ultimately settled on this, which defines which dependencies need to be pulled in so that I can hand that list to Require --%>
<div
data-recompile
data-recompile-controller="ProfileIncludeCtrl"
data-recompile-dependencies="/assets/js/profile/profileItemPageService.js,/assets/js/profile/profileItemService.js,/assets/js/profile/profileIncludeController.js,/assets/js/profile/profileIncludeDirectives.js"
data-recompile-finished="false"
class="profile-include"
data-ng-class="{'form-horizontal': !params.edit}">
<profile-item-list-directive></profile-item-list-directive>
<profile-item-page-right-panel-directive></profile-item-page-right-panel-directive>
</div>
Перекомпилируйте Директива:
myApp.directive('recompile', function($window, $q) {
return {
restrict: 'A',
link: function ($scope, elem, attrs) {
if($(elem).attr('data-recompile-finished') == 'true') return;
var dependencies = $(elem).attr('data-recompile-dependencies').split(',');
function recompiler() {
$(elem).attr('data-recompile-finished', 'true');
$(elem).attr('data-ng-controller', $(elem).attr('data-recompile-controller')); // Link the angular controller
var queue = myApp._invokeQueue;
for (var i = queueLen; i < queue.length; i++) {
var call = queue[i];
var provider = providers[call[0]];
if (provider) {
provider[call[1]].apply(provider, call[2]);
}
}
if ($('[data-ng-app="myApp"]').injector()) {
$('[data-ng-app="myApp"]').injector().invoke(function ($compile, $rootScope) {
$compile($(elem))($rootScope);
});
}
}
requirejs(dependencies, recompiler);
}
};
});
Соответствующая часть внешнего контроллера (определено в profileIncludeController.js
):
myApp.controller('ProfileIncludeCtrl', function($scope, $rootScope, $resource, $timeout, ProfileItemService, ProfileItemPageService) {
$scope.items = [];
$scope.params = [];
$scope.params = buildParamsObject(params);
$scope.items = itemsData.data || [];
});
Соответствующие части директив (определены в profileIncludeDirectives.js
). Эти директивы транслируются, потому что они должны иметь доступ к области доступа друг друга, а также к некоторым функциям, которые находятся в ProfileIncludeCtrl
, потому что эти функции действительно не принадлежали ни одной из директив.
myApp.directive('profileItemListDirective', function($rootScope, $timeout) {
return {
restrict : 'E',
templateUrl : 'profileItemList.jsp',
replace: true,
transclude : true,
scope : true,
controller : function($scope, ProfileItemService, ProfileItemPageService) {
console.log("listDirective controller");
},
link : function($scope, element, attrs) {
console.log("listDirective link");
}
};
});
myApp.directive('profileItemPageRightPanelDirective', function($rootScope, $timeout) {
return {
restrict : 'E',
templateUrl : 'profileItemPageRightPanel.jsp',
replace: true,
transclude : true,
scope : true,
controller : function($scope, ProfileItemService, ProfileItemPageService) {
console.log("panelDirective controller");
},
link : function($scope, element, attrs) {
console.log("panelDirective link");
// $scope.params is not defined here, but I need and expect it to be
}
};
});
Любые указания будут оценены!