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
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 🙂
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(); }]); });