angular-ui-router с requirejs, ленивая загрузка контроллера
Не могли бы вы помочь мне понять, как загрузить контроллер в приведенном ниже примере перед представлением? Похоже, что представление загружается сразу, а контроллер еще не загружен.
//app.js
$stateProvider.state('index', {
url: "/",
views: {
"topMenu": {
templateUrl: "/Home/TopMenu",
controller: function($scope, $injector) {
require(['controllers/top-menu-controller'], function(module) {
$injector.invoke(module, this, { '$scope': $scope });
});
}
}
}
});
//top-menu-controller.js
define(['app'], function (app) {
app.controller('TopMenuCtrl', ['$scope', function ($scope) {
$scope.message = "It works";
}]);
});
//Home/TopMenu
<h3>TopMenu</h3>
<div ng-controller="TopMenuCtrl">
{{message}}
</div>
2 ответа
Я создал рабочий плункер здесь.
Давайте иметь этот index.html:
<!DOCTYPE html>
<html>
<head>
<title>my lazy</title>
</head>
<body ng-app="app">
<a href="#/home">#/home</a> // we have three states - 'home' is NOT lazy
<a href="#/">#/</a> - index // 'index' is lazy, with two views
<a href="#/other">#/other</a> // 'other' is lazy with unnamed view
<div data-ui-view="topMenu"></div>
<div data-ui-view=""></div>
<script src="angular.js"></script> // standard angular
<script src="angular-ui-router.js"></script> // and ui-router scritps
<script src="script.js"></script> // our application
<script data-main="main.js" // lazy dependencies
src="require.js"></script>
</body>
</html>
Давайте соблюдать main.js
- конфиг RequireJS:
require.config({
//baseUrl: "js/scripts",
baseUrl: "",
// alias libraries paths
paths: {
// here we define path to NAMES
// to make controllers and their lazy-file-names independent
"TopMenuCtrl": "Controller_TopMenu",
"ContentCtrl": "Controller_Content",
"OtherCtrl" : "Controller_Other",
},
deps: ['app']
});
На самом деле, мы создаем только псевдонимы (пути) для наших ControllerNames
- и их Controller_Scripts.js
файлы. Вот и все. Кроме того, мы возвращаемся, чтобы запросить приложение, но позже мы будем использовать другую функцию - для регистрации лениво загруженных контроллеров.
что это deps: ['app']
имею в виду? Во-первых, нам нужно предоставить файл app.js ("приложение" означает найти app.js
):
define([], function() {
var app = angular.module('app');
return app;
})
это возвращаемое значение является тем, которое мы можем запросить в каждом загруженном асинхронном файле
define(['app'], function (app) {
// here we would have access to the module("app")
});
Как мы будем лениво загружать контроллеры? Как уже доказано здесь для ngRoute
AngularAMD v0.2.1
angularAMD - это утилита, которая облегчает использование RequireJS в приложениях AngularJS, поддерживающих загрузку по требованию сторонних модулей, таких как angular-ui.
Мы будем просить угловой для ссылки на $controllerProvider
- и использовать его позже, чтобы зарегистрировать контроллеры.
Это первая часть нашего script.js:
// I. the application
var app = angular.module('app', [
"ui.router"
]);
// II. cached $controllerProvider
var app_cached_providers = {};
app.config(['$controllerProvider',
function(controllerProvider) {
app_cached_providers.$controllerProvider = controllerProvider;
}
]);
Как мы видим, мы только что создали приложение 'app', а также создали держатель app_cached_providers
(следуя стилю angularAMD). На этапе конфигурации мы просим угловой для $controllerProvider
и сохранить ссылку на это.
Теперь давайте продолжим в script.js:
// III. inline dependency expression
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$urlRouterProvider
.otherwise("/home");
$stateProvider
.state("home", {
url: "/home",
template: "<div>this is home - not lazily loaded</div>"
});
$stateProvider
.state("other", {
url: "/other",
template: "<div>The message from ctrl: {{message}}</div>",
controller: "OtherCtrl",
resolve: {
loadOtherCtrl: ["$q", function($q) {
var deferred = $q.defer();
require(["OtherCtrl"], function() { deferred.resolve(); });
return deferred.promise;
}],
},
});
}
]);
Эта часть выше показывает декларацию двух государств. Один из них - 'home'
стандартный, ленивый Это контроллер неявный, но стандарт может быть использован.
Второй штат называется "other"
которая нацелена на безымянный вид ui-view=""
, И здесь мы видим, во-первых, ленивый груз. Внутри решимости (см.:)
Разрешить
Вы можете использовать решимость, чтобы предоставить вашему контроллеру контент или данные, настроенные для данного состояния. resolv - это необязательная карта зависимостей, которая должна быть введена в контроллер.
Если какие-либо из этих зависимостей являются обещаниями, они будут разрешены и преобразованы в значение до того, как будет создан экземпляр контроллера и будет вызвано событие $ stateChangeSuccess.
С этим в нашем наборе мы знаем, что контроллер (по его имени) будет найден в угловом репозитории, как только будет завершено разрешение:
// this controller name will be searched - only once the resolve is finished
controller: "OtherCtrl",
// let's ask RequireJS
resolve: {
loadOtherCtrl: ["$q", function($q) {
// wee need $q to wait
var deferred = $q.defer();
// and make it resolved once require will load the file
require(["OtherCtrl"], function() { deferred.resolve(); });
return deferred.promise;
}],
},
Хорошо, теперь, как упоминалось выше, основной содержит этот псевдоним def
// alias libraries paths
paths: {
...
"OtherCtrl" : "Controller_Other",
А это значит, что файл "Controller_Other.js" будет найден и загружен. Это его содержание, которое делает магию. Наиболее важным здесь является использование ранее кэшированной ссылки на $controllerProvider
// content of the "Controller_Other.js"
define(['app'], function (app) {
// the Default Controller
// is added into the 'app' module
// lazily, and only once
app_cached_providers
.$controllerProvider
.register('OtherCtrl', function ($scope) {
$scope.message = "OtherCtrl";
});
});
хитрость не в том, чтобы использовать app.controller()
но
$controllerProvider.Register
Служба $ controller используется Angular для создания новых контроллеров. Этот провайдер разрешает регистрацию контроллера через
register()
метод.
Наконец, есть другое определение состояния с более узким разрешением... попытка сделать его более читабельным:
// IV ... build the object with helper functions
// then assign to state provider
var loadController = function(controllerName) {
return ["$q", function($q) {
var deferred = $q.defer();
require([controllerName], function() {deferred.resolve(); });
return deferred.promise;
}];
}
app.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
var index = {
url: "/",
views: {
"topMenu": {
template: "<div>The message from ctrl: {{message}}</div>",
controller: "TopMenuCtrl",
},
"": {
template: "<div>The message from ctrl: {{message}}</div>",
controller: "ContentCtrl",
},
},
resolve : { },
};
index.resolve.loadTopMenuCtrl = loadController("TopMenuCtrl");
index.resolve.loadContentCtrl = loadController("ContentCtrl");
$stateProvider
.state("index", index);
}]);
Выше мы видим, что мы разрешаем два контроллера для обоих / всех именованных представлений этого состояния.
Вот и все. Каждый контроллер, определенный здесь
paths: {
"TopMenuCtrl": "Controller_TopMenu",
"ContentCtrl": "Controller_Content",
"OtherCtrl" : "Controller_Other",
...
},
будет загружен через разрешение и $controllerProvider
- через RequireJS - лениво. Проверьте, что все здесь
Аналогичные вопросы и ответы: AngularAMD + ui-router + имя динамического контроллера?
В одном проекте я использовал ленивую загрузку контроллеров и должен был вручную вызвать $digest для области видимости, чтобы он работал. Я думаю, что это поведение не меняется с UI-маршрутизатором. Ты пробовал это?
define(['app'], function (app) {
app.controller('TopMenuCtrl', ['$scope', function ($scope) {
$scope.message = "It works";
$scope.$digest();
}]);
});