注册 lazyloaded controller AngularJS

9
我希望可以这样加载控制器:

我想要这样加载控制器:

.state({
    name: 'app.search',
    url: 'search?q&opts',
    templateUrl: '/templates/search.html',
    controller: 'SearchCtrl',
    resolve: {
        deps: function($util){
            return $util.load(['/ctrl/SearchCtrl.js']);
        }
    }
})

控制器已加载但我遇到了以下错误,导致我认为控制器没有被注册:

参数 'SearchCtrl' 不是函数,而是未定义的

我的问题是,当按照下面所示的方式懒加载控制器时,我应该如何注册控制器。

控制器的定义如下:

app.module('app').controller('SearchCtrl',function(){

});

有什么办法可以强制控制器注册吗?

编辑 应用程序已经构建完成,一切运作良好。这个问题只涉及到惰性加载。

问题正如所述,因为引导过程已经运行,所以控制器未注册。我正在寻找在惰性加载时注册控制器的方法。

我的加载器函数 ($util.load()) 如下:

load: function (){

    if(arguments.length > 1){
        var items = arguments;
    }else{
        var items = arguments[0];
    }



    var _self = this;

    return $q(function(resolve,reject){
        if(items.length == 0){
            return resolve();
        }
        _self.async( items, function(item,next){
            if(item.indexOf('.js') != -1){
                _self.loadOne('script',item,next,function(err){
                    next(err);
                }); 
            }
            else if(item.indexOf('.css') != -1){
                _self.loadOne('link',item,next);
            }else{

                next();
            }
        },function(errors,results){
            $timeout(function() {
                $rootScope.$apply();// @Claies suggestion
                if(errors){
                    reject(errors);
                }else{
                    resolve();
                }
            });
        });
    });

},

你是否有单独声明的模块? - Sajeetharan
1
在您的加载器加载和执行控制器文件之后,但在返回解析之前,您需要使用$rootScope.$apply()。您还可以使用专为此任务设计的模块,例如oc-lazyLoad。https://oclazyload.readme.io/docs/with-your-router - Claies
@Claies 谢谢,我会试一下。 - r3wt
1
你可能需要“代理”你的控制器,这样你就可以在开始时注册代理,而不加载控制器代码,并在需要时加载控制器。这个slideshare包含一些有用的提示https://www.slideshare.net/nirkaufman/angularjs-lazy-loading-techniques。它只是一个工作示例,因为它们使用require.js(也有oclazyload,但对于你的需求只需要require即可),而你想要手动完成。但它给出了很好的提示。我不知道我是否有时间写一个答案,希望今天能够完成。 - Massimo Petrus
1
我知道,实际上我认为你必须手动实现你的代理。 - Massimo Petrus
显示剩余5条评论
1个回答

2

我通过覆盖angular.module()的自定义函数来解决了这个问题,在该自定义函数中,我将对appInstance.controller的调用传递给$controllerProvider.register()。虽然我不确定这样做是否正确,但它可以正常工作,只要不会出现任何故障,我都不太在意。

var mod = angular.module('myModule',[]); //define my module

mod.config(['$controllerProvider',function($controllerProvider){

    mod._cRegister = $controllerProvider;//store controllerProvider onto the app instance.

    var mFunc = angular.module; // copy actual module function from angular

    //override angular.module with custom function
    angular.module = function(){

        var app = mFunc.apply(this,arguments);// proxy to the real angular.module function to get an app instance

        var cFunc = app.controller;//copy actual controller function from app instance

        app.controller = function(){

            mod._cRegister.register.apply(this,arguments); // try register on the controllerProvider instance as well


            return this;//return app instance so user can chain calls or whatever.

        }.bind(app);

        return app;//return app instance, just as angular does.

    }.bind(angular);    

}]);

//rest of module code (including the loader)

这个很好用,但是只适用于控制器。下面是一个完整的示例,包括控制器、指令、组件、工厂、服务、值、常量和过滤器:

var mod = angular.module('myModule',[]);

mod.config(['$controllerProvider','$compileProvider','$filterProvider','$provide',function($controllerProvider,$compileProvider,$filterProvider,$provide){

    mod.$controllerProvider = $controllerProvider;
    mod.$compileProvider = $compileProvider;
    mod.$filterProvider = $filterProvider;
    mod.$provide = $provide;

    var map = {
        controller: ['$controllerProvider','register'],
        filter: ['$filterProvider','register'],
        service: ['$provide','service'],
        factory: ['$provide','factory'],
        value: ['$provide','value'],
        constant: ['$provide','constant'],
        directive: ['$compileProvider','directive'],
        component: ['$compileProvider','component']
    };

    var bootStrapped = [];

    var mFunc = angular.module;

    angular.module = function(){

        var app = mFunc.apply(this,arguments);

        //only override properties once.
        if(bootStrapped.indexOf(arguments[0]) == -1){
            for(var type in map){

                var c = mod;

                var d = map[type];

                for(var i=0;i<d.length;i++){
                    c = c[d[i]];// recurse until reaching the function
                }
                //now inject the function into an IIFE so we ensure its scoped properly
                !function(app,type,c){
                    app[type] = function(){
                        c.apply(this,arguments);
                        return this;//return the app instance for chaining.
                    }.bind(app);    
                }(app,type,c);
            }   
            bootStrapped.push(arguments[0]);//mark this instance as properly monkey patched
        }

        return app;

    }.bind(angular);    

}]);

@Disfigure 如果你需要一个用于懒加载的小型库,我在github/bower上有一个名为ng-util的包。它不仅仅是懒加载,还可以执行各种操作,例如同步和异步迭代器(函数队列)并保证返回顺序,以及一些随机指令和过滤器。全部只有约2.8kb。 - r3wt
很高兴听到这个消息,我已经寻找类似的东西有一段时间了。如果你有其他有用的包,请不要犹豫哈哈。 - Disfigure

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接