Over a million developers have joined DZone.

Lazy-loading AngularJS components using Providers

DZone's Guide to

Lazy-loading AngularJS components using Providers

· Web Dev Zone ·
Free Resource

Access over 20 APIs and mobile SDKs, up to 250k transactions free with no credit card required

 I've been working on an Angular project for sometime now and I usually run across issues when building the application. In most of the example applications that I've seen, all application script files are loaded upfront i.e. all JavaScript files are loaded when the user accesses application. I get annoyed by this approach; why should all the components be loaded upfront when the probability of user accessing the entire application is very less. How does one architect a multi-page application using Angular? What would be the size of the application after minifying all the JavaScript files. Most importantly how does one load the components lazily. I've used RequireJS in my previous projects and it allows you to load components on demand; the idea is to load components based on the selected route. I've tried a similar approach with Angular using 'resolve' property in the $routeProvider.

The 'resolve' property in Angular can be used to resolve services but essentially it's a promise object that gets resolved. In my previous post, I've explained how the resolve property is used to invoke a route only after resolving a $http service. Similarly, you can load the controller and service components (JavaScript files) before invoking the route. In this example, I've used RequireJS to load the controller and service components:

	.when('/login', {
		templateUrl: 'components/login/partials/login.html',
		resolve: {
			load: ['$q', '$rootScope', function ($q, $rootScope) {

				var deferred = $q.defer();

				require ([
				], function () {

				   $rootScope.$apply(function () {


				return deferred.promise;
In the above code snippet, files 'components/login/controllers/loginController' and 'components/login/services/loginService' are loaded using RequireJS. Once these files are loaded, the $rootScope.$apply function is called and the promise object is resolved in the callback handler. Although this seemed like a direct approach to resolving dependencies, Angular throws an error when you access the route. It throws 'function got undefined' error. The reason to this is, when Angular initializes or bootstraps the application, functions - controller, service etc,. are available on the module instance. Here, we are lazy loading the components and the functions are not available at a later point; therefore we must use the various provider functions and register these components. The providers are available only in the config method and hence we will have to store a reference of these providers in the config function when the application is initialized:
    function ($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {

        //router definition here

        //store a reference to various provider functions
        window.app.components = {
            controller: $controllerProvider.register,
            service: $provide.service

Here a reference to the $controllerProvider.register and $provide.service are stored in the 'app.components' object. Now when you create components, these reference variables should be used. For example, to create a 'loginController' component, the function signature would be:
At run-time the components are registered by Angular using the various provider services. Next step in refining this example is to use modules in r.js (RequireJS optimizer) to create single JavaScript files that define all the dependencies for the page.

Take a look at this git repo which contains two pages and components are loaded on demand -  https://github.com/sagar-ganatra/angular-require-resolve/

#1 for location developers in quality, price and choice, switch to HERE.


Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}