AngularJS: lazy loading controllers and content

后端 未结 9 823
小鲜肉
小鲜肉 2020-12-02 19:00

In this simplified scenario, I have two files: index.htm, lazy.htm.

index.htm:

var myApp = angular.module(\'myApp\', []);
myApp.controller(\'embed\',         


        
相关标签:
9条回答
  • 2020-12-02 19:29

    At first I utilized André Betiolo's answer. However, it does not always work becasue the ajax loading is non-blocking causing the view to sometimes request the controller prior to the script being loaded.

    As a solution i forced the function not to return until all scripts successfully loaded. This is kind of hackish but makes sure the loads are successful prior to completing the resolve. It also allows for loading of multiple controllers.

    app.js

    var app = angular.module ('app', ['ngRoute']);
    
    app.config(['$routeProvider', '$controllerProvider', function($routeProvider, $controllerProvider){
    
        /*Creating a more synthesized form of service of $ controllerProvider.register*/
        app.registerCtrl = $controllerProvider.register;
    
        //jquery to dynamically include controllers as needed
        function controllers(controllers){
            var numLoaded = 0;
            for (i = 0; i < controllers.length; i++) {
                $.ajaxSetup({async:false});
                $.getScript('js/controllers/' + controllers[i] + '.js').success(function(){
                    numLoaded++;
                    if (numLoaded == controllers.length) {
                        return true; //only return after all scripts are loaded, this is blocking, and will fail if all scripts aren't loaded.
                    }
                });
            }
        }
    
        $routeProvider
            .when('/', {
                templateUrl: 'views/foo.html',
                resolve: {
                    load: function () {
                        controllers(['foo'])
                    }
                }
            })
            .when('/bar',{
                templateUrl: 'views/bar.html',
                controller: 'BarCtrl',
                resolve: {
                    load: function () {
                        controllers(['bar','foo']) //you can load multiple controller files
                    }
                }
            })
            .otherwise({
                redirectTo: document.location.pathname
            });
    }]);
    

    /views/foo.html

    <section ng-controller='FooCtrl'>
        {{text}}
    </section>
    

    /views/bar.html

    <section ng-controller='BarCtrl'>
        {{text2}}
    </section>
    <section ng-controller='FooCtrl'>
        {{text}}
    </section>
    

    /controllers/bar.js

    app.registerCtrl('BarCtrl',function($scope){
        $scope.text2 = 'Test';
    });
    
    0 讨论(0)
  • 2020-12-02 19:31

    The best way to do what you are asking is to instead use a directive and tie the controller and template together that way so its bound at the appropriate time. Currently, the binding it not happening in lazy.htm at the right time unless you declare a global function as you've shown in your second example.

    0 讨论(0)
  • 2020-12-02 19:32

    ////JConfig file--------

    window.angularApp.config(function ($routeProvider,$controllerProvider,$compileProvider,$provide, azMessages) {
    
    $routeProvider.when('/login', {
                 resolve: {
                     load: ['$q', '$rootScope', function ($q, $rootScope) {
                         var deferred = $q.defer();
                         require([
    
                             //load required Js file here
    
                    ], function () {
                        $rootScope.$apply(function () {
                            deferred.resolve();
                        });
                    });
                         return deferred.promise;
                     } ]
                 }
             });
    
    
      $routeProvider.otherwise({ redirectTo: '/login' });
    
        window.angularApp.components = {
            controller: $controllerProvider.register,
            service: $provide.service,
            directive: $compileProvider.directive
        }
    

    //contoller declaration

    angularApp.components.controller('DiscussionController',[function(){
    
    }]);
    
    0 讨论(0)
  • 2020-12-02 19:33

    Try this ARI plugin for Angular JS. It helps you to lazy load the controller scripts on demand.

    0 讨论(0)
  • 2020-12-02 19:39

    I am sending you sample code. It is working fine for me. So please check this:

    var myapp = angular.module('myapp', ['ngRoute']);
    
    /* Module Creation */
    var app = angular.module('app', ['ngRoute']);
    
    app.config(['$routeProvider', '$controllerProvider', function ($routeProvider, $controllerProvider) {
    
    app.register = {
        controller: $controllerProvider.register,
        //directive: $compileProvider.directive,
        //filter: $filterProvider.register,
        //factory: $provide.factory,
        //service: $provide.service
    };
    
    
    //    so I keep a reference from when I ran my module config
    function registerController(moduleName, controllerName) {
        // Here I cannot get the controller function directly so I
        // need to loop through the module's _invokeQueue to get it
        var queue = angular.module(moduleName)._invokeQueue;
        for (var i = 0; i < queue.length; i++) {
            var call = queue[i];
            if (call[0] == "$controllerProvider" &&
               call[1] == "register" &&
               call[2][0] == controllerName) {
                app.register.controller(controllerName, call[2][1]);
            }
        }
    }
    
    
    var tt = {
        loadScript:
    function (path) {
        var result = $.Deferred(),
        script = document.createElement("script");
        script.async = "async";
        script.type = "text/javascript";
        script.src = path;
        script.onload = script.onreadystatechange = function (_, isAbort) {
            if (!script.readyState || /loaded|complete/.test(script.readyState)) {
                if (isAbort)
                    result.reject();
                else {
                    result.resolve();
                }
            }
        };
        script.onerror = function () { result.reject(); };
        document.querySelector(".shubham").appendChild(script);
        return result.promise();
    }
    }
    
    function stripScripts(s) {
        var div = document.querySelector(".shubham");
        div.innerHTML = s;
        var scripts = div.getElementsByTagName('script');
        var i = scripts.length;
        while (i--) {
            scripts[i].parentNode.removeChild(scripts[i]);
        }
        return div.innerHTML;
    }
    
    
    function loader(arrayName) {
        return {
            load: function ($q) {
                stripScripts(''); // This Function Remove javascript from Local
                var deferred = $q.defer(),
                map = arrayName.map(function (obj) {
                    return tt.loadScript(obj.path)
                    .then(function () {
                        registerController(obj.module, obj.controller);
                    })
                });
    
                $q.all(map).then(function (r) {
                    deferred.resolve();
                });
                return deferred.promise;
            }
        };
    };
    
    
    
    $routeProvider
        .when('/first', {
            templateUrl: '/Views/foo.html',
            resolve: loader([{ controller: 'FirstController', path: '/MyScripts/FirstController.js', module: 'app' },
                { controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' }])
        })
    
        .when('/second', {
            templateUrl: '/Views/bar.html',
            resolve: loader([{ controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' },
            { controller: 'A', path: '/MyScripts/anotherModuleController.js', module: 'myapp' }])
        })
        .otherwise({
            redirectTo: document.location.pathname
            });
    }])
    

    And in HTML Page:

    <body ng-app="app">
    
    <div class="container example">
        <!--ng-controller="testController"-->
    
        <h3>Hello</h3>
    
        <table>
            <tr>
                <td><a href="#/first">First Page </a></td>
                <td><a href="#/second">Second Page</a></td>
            </tr>
        </table>
    
    
    
    
            <div id="ng-view" class="wrapper_inside" ng-view>
            </div>
        <div class="shubham">
        </div>
    </div>
    

    Thank U

    0 讨论(0)
  • 2020-12-02 19:40

    Ideally - Angular will force you to separate HTML and JS as in newer versions this may be enforced more often.

    You may have to use requireJS http://solutionoptimist.com/2013/09/30/requirejs-angularjs-dependency-injection/

    For the sake of trick can you try

    ng-controller-controller="'lazy'"
    

    or

    In HTML

    ng-controller-controller="myObject.controller"

    Somewhere inject

    $scope.myObject.controller = $controller('lazy', {$scope: $scope})
    
    0 讨论(0)
提交回复
热议问题