Ответ 1
I создал рабочий плункер здесь.
Пусть этот 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.
Мы запросим angular ссылку $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_cached_providers
(после стиля angularAMD). В фазе конфигурации мы запросим angular для $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=""
. И здесь мы можем сначала увидеть, ленивый груз. Внутри разрешить (см.::)
Resolve
Вы можете использовать решение, чтобы предоставить вашему контроллеру контент или данные, которые являются обычными для состояния. Решение - это необязательная карта зависимостей, которые должны быть введены в контроллер.
Если какая-либо из этих зависимостей promises, они будут разрешены и преобразованы в значение до создания экземпляра контроллера, а событие $stateChangeSuccess будет запущено.
В нашем пакете мы знаем, что контроллер (по его имени) будет искать в репозитории angular после завершения решения:
// this controller name will be searched - only once the resolve is finished
controller: "OtherCtrl",
// let 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 - лениво. Убедитесь, что все здесь
Аналогичные Q и A: AngularAMD + ui-router + имя динамического контроллера?