roteador angular-ui com requirejs, carregamento lento do controlador

Você poderia me ajudar a entender como carregar o controlador no exemplo abaixo antes da exibição? Parece que a exibição é carregada imediatamente, enquanto o controlador ainda não está carregado.

//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 

TopMenu

{{message}}

Eu criei plunker de trabalho aqui.

Vamos ter esse index.html :

    my lazy   #/home // we have three states - 'home' is NOT lazy #/ - index // 'index' is lazy, with two views #/other // 'other' is lazy with unnamed view 
// standard angular // and ui-router scritps // our application

Vamos observar o main.js – a configuração do 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'] }); 

Na verdade, apenas criamos aliases (caminhos) para nossos nomes ControllerNames – e seus arquivos Controller_Scripts.js . É isso aí. Além disso, voltamos a exigir o aplicativo, mas, no nosso caso, usaremos resources diferentes posteriormente – para registrar controladores carregados de maneira lenta.

o que os deps: ['app'] significam? Em primeiro lugar, precisamos fornecer o arquivo app.js (o ‘app’ significa find app.js ) :

 define([], function() { var app = angular.module('app'); return app; }) 

este valor retornado é aquele que podemos pedir em cada arquivo carregado asynchronous

 define(['app'], function (app) { // here we would have access to the module("app") }); 

Como vamos carregar os controladores preguiçosamente? Como já provado aqui para o ngRoute

angularAMD v0.2.1

O angularAMD é um utilitário que facilita o uso do RequireJS em aplicativos AngularJS que suportam o carregamento sob demanda de módulos de terceiros, como o angular-ui.

Perguntaremos ao angular por uma referência ao $controllerProvider – e usá-loemos mais tarde, para registrar os controladores.

Esta é a primeira parte do nosso 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; } ]); 

Como podemos ver, acabamos de criar o aplicativo ‘app’ e também, criamos o app_cached_providers (seguindo o estilo angularAMD) . Na fase de configuração, pedimos angular por $controllerProvider e mantemos referência para isso.

Agora vamos continuar em script.js :

 // III. inline dependency expression app.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) { $urlRouterProvider .otherwise("/home"); $stateProvider .state("home", { url: "/home", template: "
this is home - not lazily loaded
" }); $stateProvider .state("other", { url: "/other", template: "
The message from ctrl: {{message}}
", controller: "OtherCtrl", resolve: { loadOtherCtrl: ["$q", function($q) { var deferred = $q.defer(); require(["OtherCtrl"], function() { deferred.resolve(); }); return deferred.promise; }], }, }); } ]);

Esta parte acima mostra a declaração de dois estados. Um deles – 'home' é padrão nenhum preguiçoso. Seu controlador é implícito, mas o padrão pode ser usado.

O segundo é o estado chamado "other" que tem como alvo a visão sem nome ui-view="" . E aqui podemos ver primeiro a carga preguiçosa. Dentro da resolução (veja 🙂

Resolver

Você pode usar a resolução para fornecer ao seu controlador conteúdo ou dados personalizados para o estado. resolve é um mapa opcional de dependencies que deve ser injetado no controlador.

Se qualquer uma dessas dependencies forem promises , elas serão resolvidas e convertidas em um valor antes de o controlador ser instanciado e o evento $ stateChangeSuccess ser acionado.

Com isso em nosso conjunto, sabemos que o controlador (por seu nome) será pesquisado no repository angular assim que a resolução terminar:

 // 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; }], }, 

Bom, agora, como mencionado acima, o main contém esse alias def

 // alias libraries paths paths: { ... "OtherCtrl" : "Controller_Other", 

E isso significa que o arquivo “Controller_Other.js” será pesquisado e carregado. Este é o seu conteúdo que faz a mágica . O mais importante aqui é o uso de referência anteriormente armazenada em cache para $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"; }); }); 

o truque não é usar app.controller() mas

$controllerProvider.Register

O serviço $ controller é usado pelo Angular para criar novos controladores. Esse provedor permite o registro do controlador através do método register() .

Finalmente, há outra definição de estado, com uma resolução mais restrita … uma tentativa de torná-lo mais legível:

 // 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: "
The message from ctrl: {{message}}
", controller: "TopMenuCtrl", }, "": { template: "
The message from ctrl: {{message}}
", controller: "ContentCtrl", }, }, resolve : { }, }; index.resolve.loadTopMenuCtrl = loadController("TopMenuCtrl"); index.resolve.loadContentCtrl = loadController("ContentCtrl"); $stateProvider .state("index", index); }]);

Acima podemos ver que resolvemos dois controladores para ambas / todas as visualizações nomeadas desse estado

É isso aí. Cada controlador definido aqui

 paths: { "TopMenuCtrl": "Controller_TopMenu", "ContentCtrl": "Controller_Content", "OtherCtrl" : "Controller_Other", ... }, 

será carregado via resolve e $controllerProvider – via RequireJS – preguiçosamente. Verifique que tudo aqui

Perguntas e respostas semelhantes: AngularAMD + roteador-ui + nome do controlador dynamic?

Em um projeto eu usei o carregamento lento de controladores e tive que chamar manualmente um $ digest no escopo para que ele funcionasse. Eu acho que esse comportamento não muda com o roteador ui. Você tentou isso?

 define(['app'], function (app) { app.controller('TopMenuCtrl', ['$scope', function ($scope) { $scope.message = "It works"; $scope.$digest(); }]); });