Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

register lazyloaded controller angularjs

I want to load controllers like so:

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

The controller loads but i get the following error, leading me to believe that the controller was not registered:

Argument 'SearchCtrl' is not aNaNunction, got undefined

So my question is, how would i go about registering the controller when loading it lazily as shown.

controller is defined as:

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

});

Is there anything i can do to force the controller to be registered?

EDIT THE APP IS ALREADY BUILT AND ALL WORKS FINE. THIS QUESTION PERTAINS TO LAZYLOADING ONLY.

The problem is exactly as defined, the controller is not registered because the bootstrapping process has already run. i'm looking for some way to register the controller when it is lazyloaded.

my loader function ($util.load() looks like so:

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

},
like image 364
r3wt Avatar asked Feb 22 '17 17:02

r3wt


People also ask

Can you create controller in AngularJS?

In AngularJS, a controller is defined by a Javascript construction function, which is used in AngularJS scope and also the function $scope) is defined when the controller is defining and it returns the concatenation of the $scope. firstname and $scope. lastname.

Does AngularJS support lazy loading?

AngularJS doesn't officially support lazy loading of components, services, etc. However, third party libraries such as ocLazyLoad provide this functionality. Lazy loading components is very simple with UI-Router and ocLazyLoad. The component is loaded and registered with ocLazyLoad, then the state is activated.

How is lazy loading implemented in AngularJS?

To enable lazy loading, we need to update the routing config to indicate that some modules will be loaded on route execution: import { ModuleWithProviders } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { HomeComponent } from '../home/home.

What is ocLazyLoad in AngularJS?

OcLazyLoad is used to load the dependency files and also to inject the AngularJS modules on the fly. Loading Js and Css files are effortless. We can't maintain the dependency files structure.


1 Answers

I was able to solve it myself by overriding angular.module() with a custom function, and within this custom function i pass calls to appInstance.controller to $controllerProvider.register(). it is working, i'm not sure how proper it is but i don't really care as long as it doesn't break anything.

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)

This works great, but only for controllers. following is a full example covering controllers, directives, components, factories, services, values, constants, and filters:

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);    

}]);
like image 85
r3wt Avatar answered Oct 25 '22 06:10

r3wt