angular-ui-router mit requires, lazy laden des controllers

Könntest du mir helfen zu verstehen, wie man den Controller im folgenden Beispiel vor der Ansicht lädt? Es sieht so aus, als ob die Ansicht sofort geladen wird, während der Controller noch nicht geladen ist.

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

   

    Ich habe hier einen funktionierenden Plünderer geschaffen .

    Lass uns diese index.html haben :

     < !DOCTYPE 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

    Betrachten wir die main.js – die RequireJS config:

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

    Tatsächlich erstellen wir nur Aliasnamen (Pfade) für unsere ControllerNames – und ihre Controller_Scripts.js Dateien. Das ist es. Auch wir kommen zurück, um die App zu benötigen, aber wir werden in unserem Fall später andere functionen verwenden – um regellos geladene Controller zu registrieren.

    Was bedeuten die deps: ['app'] ? Zuerst müssen wir die Datei app.js bereitstellen (die ‘app’ bedeutet app.js finden) :

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

    Dieser zurückgegebene Wert ist derjenige, den wir in jeder async geladenen Datei verlangen können

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

    Wie werden wir Regler träge laden? Wie schon hier für ngRoute

    angleAMD v0.2.1

    angleAMD ist ein Dienstprogramm, das die Verwendung von RequireJS in AngularJS-Anwendungen erleichtert und das On-Demand-Laden von Modulen von Drittanbietern wie angular-ui unterstützt.

    Wir werden angular nach einem Verweis auf $controllerProvider fragen – und später verwenden, um die Controller zu registrieren.

    Dies ist der erste Teil unserer 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; } ]); 

    Wie wir sehen können, haben wir gerade die Anwendung ‘app’ erstellt und auch den Halter app_cached_providers (nach dem angularAMD-Stil) erstellt . In der Config-Phase fragen wir nach angular für $controllerProvider und behalten die Referenz dafür.

    Jetzt lass uns in script.js weitermachen :

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

    Dieser Teil oben zeigt zwei Staaten Deklaration. Einer von ihnen – 'home' ist Standard kein fauler. Es ist Controller implizit, aber Standard könnte verwendet werden.

    Der zweite ist der Zustand "other" der auf die unbenannte Ansicht zielt ui-view="" . Und hier können wir zuerst sehen, die faule Last. Innerhalb der Entschlossenheit (siehe 🙂

    Entschlossenheit

    Sie können die Auflösungsoption verwenden, um Ihrem Controller Inhalte oder Daten bereitzustellen, die für den Status benutzerdefiniert sind. resolve ist eine optionale Zuordnung von Abhängigkeiten, die in den Controller injiziert werden sollen.

    Wenn eine dieser Abhängigkeiten verspricht , werden sie aufgetriggers und in einen Wert konvertiert, bevor der Controller instanziiert wird und das $ stateChangeSuccess-Ereignis ausgetriggers wird.

    In unserer Suite wissen wir, dass der Controller (nach seinem Namen) in einem eckigen Repository durchsucht wird, sobald die Lösung abgeschlossen ist:

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

    Gut, jetzt, wie oben erwähnt, enthält die Hauptversion dieses Alias ​​def

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

    Und das bedeutet, dass die Datei “Controller_Other.js” gesucht und geladen wird. Dies ist sein Inhalt, der die Magie tut. Das wichtigste hier ist die Verwendung des zuvor zwischengespeicherten Verweises auf $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"; }); }); 

    Der Trick ist nicht, app.controller() aber zu verwenden

    $controllerProvider.Register

    Der $ Controller-Dienst wird von Angular zum Erstellen neuer Controller verwendet. Dieser Provider ermöglicht die Registrierung des Controllers über die Methode register() .

    Schließlich gibt es noch eine weitere Zustandsdefinition mit engerer Auflösung … ein Versuch, sie lesbarer zu machen:

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

    Oben können wir sehen, dass wir zwei Controller für beide / alle benannten Ansichten dieses Zustandes auflösen

    Das ist es. Jeder Controller ist hier definiert

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

    wird über resolve und $controllerProvider – via RequireJS – träge geladen. Überprüfen Sie das alles hier

    Ähnliche Fragen und Antworten : AngularAMD + UI-Router + dynamische Controller-Name?

    Bei einem Projekt habe ich das Lazy-Laden von Controllern verwendet und musste manuell einen $ Digest auf dem Scope aufrufen, damit er funktioniert. Ich nehme an, dass sich dieses Verhalten mit dem UI-Router nicht ändert. Hast du das versucht?

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