Lazy Loading In AngularJS

April 21, 2013 — 84 Comments

When building large sites or apps with many routes/views in AngularJS, it would be good to not have to load all artefacts such as controllers, directives etc., on the first load. Ideally, on first load, only the artefacts that are needed for the route in question, will be loaded. This may be either in one download or multiple depending on the app, however, it will only be what is needed to render the particular route. Then as the user navigates the app by changing the route, other artefacts that have not already been loaded, will then be loaded as and when there are needed. Not only should this potential speed up the initial page load, but it should also result in bandwidth not being wasted. With this post, my aim is to show how the lazy loading of artefacts such as controllers and directives can be achieved with AngularJS.

In order to lazy load artefacts such as controllers and directives in AngularJS, there are two primary questions that will have to be answered and they are as follows:

  1. How can lazy artefacts be registered against a module after the application has already been bootstrapped?
  2. Where in the application should the actual loading take place using your script loader of choice?

The first question results from a current inability to register artefacts after application bootstrap, using the module API. In other words, if you were to try to register a new controller with an already bootstrapped app, using the following code:

you would get the following error when you reference the controller with the ng-controller directive:

Error: Argument ‘SomeLazyController’ is not a function, got undefined

Currently, the only way (that I know of) to register artifacts with an already bootstrapped application, is not to use the module API, but to use the relevant AngularJS provider instead.

Providers are essentially objects that are used to create and configure instances of AngularJS artefacts. Hence, in order to register a lazy controller, you would use the $controllerProvider. Similarly, To register a directive, you would use the $compileProvider, to register filters you would use the $filterProvider, and to register other services, you would use the $provide service. The code will look something like this for controllers and directives:

Now the thing with providers is that they are only available during module configuration. Hence, a reference to them will have to be kept so that they can be used later on to register lazy artefacts. As an example, to get a hold of the relevant providers, you could setup your app module similar to the following:

You would then be able to define a lazy controller as follows:

The question still remains, however, as to where the loading of lazy artefacts such as the above controller, will take place using your script loader of choice. Currently, there is only one place where this can happen ‘cleanly’ and it is in the ‘resolve’ property of the route definition.

When defining a route using the $routeProvider, you can specify an optional key/factory map of dependencies that should be injected into the route controller. This dependency map is specified using the ‘resolve’ property as follows:

The ‘key’ in the dependency map will be the name of the dependency, and the ‘factory’ will either be a string that is the alias of an existing service that should be used as the dependency, or an injectable function whose return value should be used as the dependency. Now if the function returns a promise, the promise will be resolved before the route is ‘rendered’ (so to speak). Thus, dependencies that have to be retrieved asynchronously, such as lazily loaded artefacts, can be retrieved using a dependency map function that returns a promise that will be resolved once the lazy artefacts have been loaded. This ensures that all lazy artefacts are loaded before the route is rendered. An example of a route definition that specifies lazy dependencies to be loaded using the $script.js script loader, is as follows:

One thing that should also be noted is that because the promise resolution will most likely be taking place outside the context of AngularJS, as in the above example, it is happening inside the $scriptjs context, AngularJS has to be explicitly told when the promise has been resolved (so to speak). This is achieved by resolving the promise inside of the $apply method of the $rootScope as in:

If the promise is not resolved inside the $apply method of the $rootScope, the route will not be rendered on the initial page load.

Now applying all this back to the app module definition, will yield the following:

Finally you can bootstrap the app using code similar to the following if using $script.js:

These are more or less the steps that you would take to implement lazy loading in AngularJS. In summary, you would first define your app module to keep instances of the relevant providers. Then you would define your lazy artefacts to register themselves using the providers rather than the module API. Then using a ‘resolve’ function that returns a promise in your route definition, you would load all lazy artefacts and resolve the promise once they have been loaded. This ensures that all lazy artefacts will be available before the relevant route is rendered. Also, don’t forget to resolve the promise inside $rootScope.$apply, if the resolution will be happening outside of AngularJS. Then you would create a ‘bootstrap’ script that first loads the app module before bootstrapping the app. Finally, you would link to the bootstrap script from your ‘index.html’ file.

To see a runnable example using Asynchronous Module Definitions with RequireJS, have a look at the sample app.

TwitterFacebookGoogle+LinkedInDiggRedditStumbleUponEmail

Ifeanyi Isitor

Posts Twitter Google+

I'm a web application developer / independent contractor, currently residing in London.
  • sam3k

    Nice article. Question, can you lazy load a controller that has been added via a ng-controller directive in the mark up?

    • ifeanyiisitor

      Thanks Sam. Yes if the controller has been referenced with a ng-controller directive in the route template, it can be lazy loaded via via the method I wrote of in this blog post. For example, taking…

      $routeProvider.when('/', {templateUrl:'views/home.html'});

      If the ng-controller directive is used in ‘views/home.html’, this method will work. The sample app shows an example of this. If the ng-controller directive is not specified in a route template, however, then you would have to make sure you load it in the regular manner before the application bootstrap as it will need to be available on first load.

      • sam3k

        Got it. So, i just clone your sample app and try doing a r.js minification to see if the lazy loaded controllers get minified but they don’t. Did I miss something? Have you been able to minify lazy loaded content?

        • ifeanyiisitor

          Yes I have been able to minify lazy loaded controllers with r.js. My intent with the sample app in this post, however, was not to demonstrate the minification with r.js, but to only provide a runnable example of what I wrote in this post. I plan to write another post that builds on this one in which I will focus on an AMD specific implementation of lazy loading. In that post r.js will be covered.

          • sam3k

            Awesome. I look forward reading the next article. Cheers.

  • Pingback: AngularJS | Pearltrees

  • Ben Nadel

    Excellent article. We have a fairly large single page app and as it starts to grow peripheral features, I’ve been meaning to look into how to lazy load the parts that don’t get used very much. This has given me a great starting point!

    • ifeanyiisitor

      Thanks Ben, I’m glad I was able to help

  • http://dewmap.com/ Brett Coffin

    Excellent article. Thanks for the insight…

  • Jesse Beard

    This is an outstanding article! Thanks for the efforts of putting this together. I look forward to your AMD article as well!

  • amir souchami

    WOW thanks so much for taking time and covering this subject in depth.
    And way to go! a very creative solution.

    Although, anyone knows if its in the AngularJS road map to provide this ability “more natively” in the api.
    Or do they consider implementing their own $script loader?

    • ifeanyiisitor

      Thanks Amir. The AngularJS team have stated that native lazy loading support is in the pipeline. It doesn’t seem to be in the published roadmap yet though.

  • PayamYousefi

    It’s great, but i’ve tested it and sometimes it loads the controller and template but doesn’t render the template.

    • ifeanyiisitor

      Good spot Payam. That’s because the promise resolution is happening outside of angular and hence angular does not realise that the resolution has taken place. It should all be working now as I have wrapped the resolution code in an angular $apply method


      $rootScope.$apply(function(){
      deferred.resolve();
      });

      Just in case it is not obvious, this just tells angular to digest after the promise is resolved.

      Cheers.

  • jinto jose

    Great article. Thanks so much for this information. I tried this application locally. I am able to move to the different views. However, once all views are rendered (upon going to each section), then, it is not getting refreshed. ie. first I am going to About, Contact, it is changing the views correctly. Again, when I click on Home link, the view is not getting changed. Still it is showing the Contact view. Am I doing something wrong? Please advise

    • ifeanyiisitor

      Hi Jinto. You are not doing anything wrong. There was a bug in the code. Thanks for spotting it. It should be fixed now. Please try again and let me know. Cheers.

  • Pingback: Lazy Loading In AngularJS | IFY I/O | Nearly Done

  • Tim Sweet

    This is nice, I wrote an ng-initialize directive a few months ago that lazy loads views and controllers based on a condition (using it in place of ng-include)

  • Stu Salsbury

    Good stuff, Ifeanyi. Thank you for the clear explanation. Is the use of $script for bootstrapping due to eventual script minimization and/or code modularization? Or is there an inherent reason to use it when you wish to lazily load your routes’ dependencies?

    • ifeanyiisitor

      Thanks Stu. You can actually use any script loader. In practice I prefer to use RequireJS as I can use the optimiser to combine multiple files into fewer for faster lazy loading. I only used $script.js in the above examples because it is what it used on the angular seed app and so I figured I would stick with that for the sake of simplicity.

  • http://profiles.google.com/eric.bichara Eric Bichara

    Great Article, i am however getting a “Error: Argument ‘Controller’ is not a function, got undefined” error. I’ve created the routing exactly like you defined above, and reference the controller from my template using data-ng-controller=”Controller”. the script seems to be getting loaded corretly but angular isnt seeing it. any suggestions? Thanks /Eric

    • ifeanyiisitor

      Hi Eric, do you have some code I can look at? Otherwise, are you using the $controllerProvider to register the controller when it is loaded?

  • Johnny Hauser

    I just did something like this….my complete explanation on it is here. http://pastebin.com/Vy3R2HCv
    I know it could be much better (especially since I had to replace $http with jQuery.ajax). I would really appreciate thoughts on this.

    • Johnny Hauser

      It turns out that the code in my original link had many bugs. I am starting to understand angular much better now and have written the directive much better (no jQuery, no bugs). I chose to insert my controller script (response from $http) as a script tag with src as data uri rather than eval(), simply to have the script appear in the resources tab of the dev tools. The downside is this causes a need for a global callback or event (something to ensure the controller is fully loaded). Here is my working directive which dynamically lazy loads a controller and view based on the url. http://pastebin.com/RsYuKTMT

  • nmrony

    your article gives me a life saving solution for a plugin currently i am developing in angularjs. and it really helps me to boost-up the performance.

    • ifeanyiisitor

      Great to hear that mmrony. Glad I could help.

  • ThomasBurleson

    I have not tried this yet… so I will ask. Does this approach also work when you lazily define modules (as one of the dependencies) and 1 or more of the other dependencies wants the module to be injected ?

    e.g.

    var dependencies = [
    'modules/TwitterServices.js',
    'controllers/CommentController.js' // which injects the $twitter sevice instance
    ];

    • ifeanyiisitor

      If $twitter is registered against the same module as the CommentController or against any other module that was loaded before application bootstrap, then this approach will work. If $twitter however has its own module definition like…


      var module = angular.module('twitter-module', []);

      module.service('$twitter', function(){
      ...
      })

      Then for it to work, the actual module declaration angular.module('twitter-module', []) should be separated and loaded before bootstrap. The $twitter service implementation can then be lazy loaded and all will work as expected.

      • ThomasBurleson

        Yes exactly… until your last paragraph (LOL). Correct me if I mis-understood.
        The point on true lazy module loading is that it can be loaded AFTER bootstrap; and it is loaded only when used.

        • ifeanyiisitor

          The point of lazy loading is to load SCRIPT FILES THAT CONTAIN NEEDED FUNCTIONALITY after bootstrap at some time when they are needed and not before. As long as the script file contains the needed functionality, that is all that matters. The module declaration does not have to be in the script file that is being lazy loaded. It can be in a separate script file that is not lazy loaded. So in my previous answer to you, what I was saying is that you would declare your modules before bootstrap in one script file like so:


          var twitterModoule = angular.module('twitter-module', []);

          twitterModoule .config(function($provide)
          {
          twitterMdoule.service = $provide.service
          })

          angular.bootstrap(document, ['app', 'twitter-module']);

          That is all that is needed. to bootstrap the app. Then at some later point after bootstrap, a script file called ‘TwitterService.js’ containing the following can be lazy loaded.


          // TwitterService.js
          angular.module('twitter.module').service('$twitter', function()
          {
          ....
          });

          This way a sort of stub module without its players is registered up front but the different players in the module are lazy loaded. With this the goal of not loading all your functionality at the beginning of the app, but instead only when they are needed, would be met. That is what is important isn’t it? Currently, lazy loading is not natively supported in angular. The point of this article is just to show one way that it can be achieved now for those who desperately need it.

          • ThomasBurleson

            Thanks for the clarity; I have found your article very helpful.

            It was the wording of you previous reply that confused me; when you mentioned before application bootstrap.
            BTW, uppercasing many words is often interpreted as yelling instead of emphasis.

          • ifeanyiisitor

            Apologies Thomas if I came across as yelling. It wasn’t my intention. I have edited the comment. I’m glad that you found the article helpful and thanks for the heads up. Cheers.

          • ThomasBurleson

            Please keep submitting your helpful blogs. +1
            And thanks for your patience with seemingly dumb replies. :-(

  • ThomasBurleson

    A critical factor [when lazy loading code/modules] is a standard use of namespacing or packages for your code. The goal of namespace[ing] is to allow you to avoid conflicts/overwrites of your code. @see https://gist.github.com/ThomasBurleson/5752142

  • Данил Сомсиков

    That’s actually very bad idea. Angular by design separated configuration from execution and explicitly disallow using providers outside of configuration blocks (see Module Loading & Dependencies at http://docs.angularjs.org/guide/module).

    This may lead to bugs and unexpected behavior since neither AngularJS neither client code expects directives and controller to appear after injector was created.

    Yes, delayed modules loading is a valid idea, but we should wait for proper support from the framework, not hack it.

    In fact there’s sane and easy way to achieve the same thing: extract asynchronous dependencies to a separate class and write your directive in a way that it will check if asynchronous code is already loaded, and do nothing while it is not there yet.

    See an awesome demo by Mircea Pricop at http://plnkr.co/edit/PiaKyz?p=preview .

    • ifeanyiisitor

      @Данил Thanks for your comment. This blog post, however, was more about showing how lazy loading could be currently achieved in angularjs as it is something that many have been enquiring about for quite a while. It is up to you to decide if it is something you want to do. Having said that though, I am of the personal belief that as long as something solves a problem that benefits the end user, even if it is supposedly a ‘hack’, it is ok to do it. Waiting for the angularjs team to implement built in lazy loading may be a very long wait. Whereas I can just have it now and when the angular team implements it, I just update my implementation. I have been successfully using this technique without any bugs and the day a bug props up that prevents my app from working, then I will stop using it. Until then I feel that having a working app that is performant with a few necessary hacks is much more important than having a not so performant app with no hacks. As a developer, I see it as my duty to hack it until it becomes native, for the sake of the end users experience. So in summary, I dont think its a bad idea. To me, nothing that benefits the end users experience is a bad idea… but thats just me. Cheers.

    • dave

      One can check whether asynchronous code has been executed by using deferred objects. If the deferred object has already been resolved, then its promise will call the .then() method immediately, and if not, it will call it when it has been resolved.

  • J Castillo

    Wonderful idea @ifeanyiisitor:disqus . Over this past year we have built a large Call Center app using #AngularJS and the index has reach its limit, is huge. We have been looking for a while for a way to lazy load the controllers and directives and de-clutter the index.html file. I pitched the idea of having a templateJS property (the same way we have templateUrl) as part of the $routeProvider for Angular 2.0, to the Angular team and apparently they liked it. We will see.

  • mc

    This does not work in angular 1.1.5, but work fine in 1.0.7

  • mc

    this doesn’t work with the new 1.1.5 version, any ideas?

  • mc

    this does not work in version 1.1.5, works fine in 1.0.7, any ideas?

    • ifeanyiisitor

      Hi mc, apologies for the delayed response. I have just verified that it works with version 1.1.5 of angularjs. You can verify it using the sample app on github https://github.com/ifyio/angularjs-lazy-loading-with-requirejs. Just replace the contents of /app/lib/angular.min.js with version 1.1.5 of angularjs.

  • kanukaclancy

    Good stuff. Anyone who balks at this being a “bad idea” should be forced to defend their annotate method as it is full of several horrible ones. The overloaded terminology and overall showiness of their DI implementation just makes me want to scream.

    While I’ve been able to get my directives registered successfully using this technique, I have not been able to convince Angular to go back and re-parse any bit of DOM that contains them this way, so those directives remain sadly dormant. Is this possible or am I dreaming up the wrong pole?

    • ifeanyiisitor

      Hi kanukaclancy, are you resolving your promise in a $rootScope.$apply method

      $rootScope.$apply(function()
      {
      deferred.resolve();
      });

      Without doing so, angular would not know to update the DOM. Cheers.

      • kanukaclancy

        I have no promise to resolve in my case. I am not performing any dynamic loading of scripts, I am merely attempting to vend a layer of abstraction that obviates the need for much of Angular’s redundant boilerplate that allows controller classes (in the classical sense of the term) to register their directives as they are instantiated at runtime.

        I’m also using the AngularUI router as the default one is too anemic and too buggy for my needs.

  • t00f

    Hey, it looks very useful article !

    I read comments about lazzy loading controllers. How can you inject your controller defined in your dependency (say AboutViewController) using controller $routeProvider parameter ?

    I would try to do something like :

    $routeProvider.when(‘/about’, {templateUrl:’views/about.html’, controller: “AboutViewController” resolve:{deps:function($q, $rootScope) { /* dynamic loading*/ }

    It actually fires me an error saying AboutViewController is not a function. Maybe it should be because the controller name “AboutViewController” is resolved before the resolve function ?

    Can you give me your opinion on that point ?

  • Srinix

    Its awesome approach. But template & controllers are not loading for me.

  • Sudipta

    Can something similar be done using ng-include.

    We have one single main page that is loaded using routeprovider. The main page includes files using ng-include.
    We include templates with something like the following

    The page also has some left menus the click handler for those menus does something like

    $scope.myMenuClick = function() {
    $scope.contentFrame=’fragment/mysecondpage.html’;
    }

    So on clicking menu the contentFrame gets changed with a different template page.

    Each template page has its own controller defined in separate files like myfirstpageController.js, mysecondpagecontroller.js

    myfirstpage.html is something like

    I want to lazily load the controllers, i.e. I want to load the mysecondpagecontroller only when that menu is clicked and not on bootstrap.

    Can someone please help me?

  • http://blog.danmasq.com Dan Masquelier

    Just experienced this error in 1.1.5 when toggling back and forth between routes:

    “$digest already in progress when calling $scope.$apply()”

    Did some research and came across this:
    http://stackoverflow.com/questions/12729122/prevent-error-digest-already-in-progress-when-calling-scope-apply

    basically if $rootScope.$$phase is true, you should just resolve your deferred since that dependency set is already loaded.

    for my deps: function($q, $rootScope) {
    var deps = ['js/controller/foo.bar.js'];
    var d = $q.defer();
    $LAB.script(deps).wait(function() {
    if ($rootScope.$$phase) return d.resolve(); // this is the fix
    $rootScope.$apply(function() { d.resolve(); });
    });
    return d.promise;
    }

  • Ciul

    Excellent article, found it very useful.
    One question: I need to resolve dependencies from a Blog service to read a post before going to the next view.

    Since controller is lazy loaded in a resolve key:function, and the post would be resolved in another. How can I pass that post to the controller that is used in the template with ng-controller?

  • Mike McElroy

    How do you unit test the controllers registered in this way? If you have angular.module(‘app’).controllerProvider.register(‘SomeLazyController’)
    at the bottom of the SomeLazyController JS file, when you load your files synchronously for testing, it throws an error, saying that controllerProvider is undefined. You can’t run the .config() function that sets up the controllerProvider because it won’t allow later-loaded modules (in the list of files to be loaded) to register themselves.

    • Blowsie

      +1

      • ifeanyiisitor

        @mike_mcelroy:disqus , @Blowsie:disqus

        I have updated the sample project to now include an example controller test. Look in the test folder. In order for it to work, I had to modify app/scripts/app.js config block to override the module methods such as app.controller, app.service etc, with the provider equivalent. That way, when running in the browser, lazy loading will be supported and when unit testing, the controllers, services etc., will be loaded in the regular way (i.e., not lazy loaded) so that they can be tested. Hope this helps.

  • kajaljatakia

    Great article! I am new to AngularJS. We have to take decision for our new big single page application( more then 300+ views and 50+ functional modules). We are trying different solution for lazy loading in AngularJS. None of the solution has a proper/Complete implementation. I got this article and created sample application based on your sample application(https://github.com/ifyio/angularjs-lazy-loading-with-requirejs). Need some light here:
    1) the above article has not used RequireJS. Do you have any sample project of AngularJS Lazy Loading without RequireJS?
    2) In your sample project of lazy loading with requireJS, unit test is not implemented. I tried but not getting through. If you have unit test case working please upload.
    Thanks for help!

  • Luudv

    Thanks for your article, i follow your instructions. But when i click to navigation menu, the controller + view haven’t call yet. What’s i missing here? Thanks

  • btubb

    Excellent article. I’m just starting to use this method with deferred routing. An excellent article on deferred routing can be found here: http://blog.brunoscopelliti.com/how-to-defer-route-definition-in-an-angularjs-web-app

    For anyone using Angular 1.2+:
    Make sure you include angular-route.js in the /lib directory and index.html, and include ‘ngRoute’ in the app.module definition (in appModule.js). It should look like:
    var app = angular.module(‘app’, ['ngRoute']);

    Angularjs now has the routing code split into this external dependency, so the latest github code will not work without these changes. Good news is that lazy loading still works in 1.2rc2!

  • kuma_d

    how ui-router can mix into angular.js with require.js ?

  • Felipe Triana Castañeda

    If you have to do additional things in resolve function for example authentication, how this can be achieved?

  • Quan

    Thanks for the great post. I’ve been meaning to use this for a while in a project and I finally have the opportunity to do that. However, I have a question about lazy-loading module dependencies. That is, instead of specifying the controllers and directives dependencies, is there a way to specify a module dependency that will be lazily registered into the app module when a route is rendered? Thanks in advance for any feedback.

    • ifeanyiisitor

      Hi Quan. As far as I’m aware, modules cannot yet be lazy loaded. What you can do though is register upfront an empty or stub module (so to speak) that you can later use to lazy load its artifacts. I know its not quite the same but its seems to be all we have for now.

  • Ddcoder

    Thank you so much for this wonderful article. I am trying to figure out how to include services in following your pattern. How would you include services and filters?

  • Macha

    How do I write a filter?

    define(['app'], function(app) {

    app.lazy.filter(‘dateObject’, [ function () {

    - The above is not working, if I use dateObject it always says “not defined”

    • Guest

      Controller, Services & Directives are working fine, if I load them the same way.

  • William McVay

    I’ve just been spending some time going over the Angular source code to determine why the original module API methods don’t work. It seems that these methods do not independently acquire references to the $providers or call any methods against them, but instead add the calls to a queue that is executed at the same time as the various ‘config’ blocks. In this context, both the config blocks and the module API calls can access the $providers and run their queued up method calls against them.

    Rather than relying on this queue, you’re using the opportunity to access the providers afforded by the config blocks to shortcut the module API so that it is no longer adding to a queue that will never be invoked again, but instead uses the direct references saved to its run context when it was overwritten to call against the $provider immediately.

    The two issues I have are:
    1. Lazy loaded asynchronous services have no mechanism for resolving the data those services provide prior to route change, only for resolving the services themselves. The controller itself would have to invoke the service and await the response, which is not ideal.

    2. This is all well and good for your demo application, but why lazy-load 3-5 files for one state? The real benefit to this design pattern accrues to much larger projects with countless fringe states, where loading the scripts defining their directives every time the application is run wastes network resources and delays application loading, and where moving modules along with their controllers, services, directives, and filters in disparate files should not require you to include every single script file as an include in the root document of your project but instead should only require you to include the module, with its dependencies loading themselves as needed.

    I came up with a solution to those issues inspired by your article. I couldn’t have done it without you. Just wanted to thank you for your help and offer a resource to some other wayward traveler who may have the same problems I did.

    http://stackoverflow.com/questions/21742495/lazy-loading-of-angular-component-scripts-when-changing-states

    • ifeanyiisitor

      Hey William,
      Thanks for your input. With regards to point 1, I’m not sure I understand what you mean . All I can say is that I have had no problem using this method in practise. Everything always resolves properly regardless of situation.

      Where point 2 is concerned, my aim was only to show the strategy or mechanics to achieve lazy loading in a simply manner that can be understood. It’s then up to you to decide how best to use it for the app and situation you are in. In terms of what you lazy load, whether it be one file at a time or you combine a group of files as one and then lazy load that, it’s up to you. I have done both. Regardless of the high level strategy I decided upon, at a lower level it would work in this way. This post was never meant to suggest a strict way of lazy loading. It was just to simply show the low level mechanics (so to speak) to achieve it so that others could have something in the firm of a simple strategy to start with when designing their own solution.

      If there is a different way to achieve lazy loading by not using providers, all well and good. I would definitely be interested in seeing it. Cheers.

      • William McVay

        You should check out my post on Stack Overflow, I posted the Angular module I came up with. The issue I’m referring to with #1 is say, if you wanted to USE the service that you’re lazy loading and resolve some of its asynchronous methods to be injected into your controllers. Since your approach loads the script and registers the provider as part of the ‘resolve’ phase of a route change, that same ‘resolve’ phase can’t inject the service you’re providing into another function since the service is still loading. You can’t hold the route change until a service call’s deferred promise resolves too. You’d have to wait until you got into the controller to actually invoke the service. That’s fine if your service is instantaneous, but if it’s a deferred, asynchronous service, your state and your controller will load well in advance of your service’s data. My solution was to interrupt the state transition (using ui-router instead of routes, personal preference) and then resume it after the scripts had loaded.

        I also think I addressed point 2 pretty well by making the whole thing a module with a registered service to load the scripts. Please take a look and let me know what you think. Please don’t mistake me, I would not have been able to get anywhere without your article pointing me to the providers. That is the only way I saw of doing it looking through the Angular source. The providers are not made available except within the functions actually responsible for bootstrapping modules, and extracting them from within a config block as you did was genius. I’m just trying to actually put your demo into a more production form and trying to explain to anyone following in my footsteps why the additional work was necessary.

        http://stackoverflow.com/questions/21742495/lazy-loading-of-angular-component-scripts-when-changing-states

        • ifeanyiisitor

          Hi William. No worries at all. I’m just happy that I was able to contribute something that you were able to build upon. As soon as I have a chance, I will definitely have a play with what you have built. Cheers.

  • http://www.mathieurobin.com/ Mathieu ROBIN

    Hi ! Your method is really great, I like it and use it everyday. Thanks ! There is just a critical problem. With that approach, I can’t find how to test it. Nothing is working, so, have you an idea on how to unit test ?

  • VishwaKumar Patil

    I am trying to implement this in one of our projects. But not able to. http://stackoverflow.com/questions/21901922/angularjs-lazy-loading-not-working

  • Cristobal diaz

    i am not tried out yet, but it looks great.
    i have waited for this since angular 0.9, now i think with 1.2 it is easier
    very good article man

  • Pingback: Unit Testing Lazily Loaded AngularJS Artefacts | IFY I/O

  • chetan

    this is really good article and excatly what I am looking for….

  • Abhishek

    I know this post is old, but still thanks for the excellent and really helpful article. We plan to use this in our project.
    One question I had is related to your corresponding sample app in Github. So in routes.js we can define all dependencies and they will be resolved when one visits a route. But what if I want to define some resolve directly in the route configuration, for ex-

    ‘/contact’: {

    templateUrl: ‘/views/contact.html’,
    dependencies: [
    'controllers/ContactViewController'
    ],
    resolve: {
    simpleObj: function() {
    return {value: ‘simple’};
    }
    }
    }

    So what I want is to combine the dependencies defined in routes.js and any resolves I define directly so that all these are injected in my controller/directives. Now I know I can define simpleObj as just another dependency and include in the list, but lets say I want to have the option to define some resolves directly. Is this possible? I tried combining the two but couldn’t make it work. Hope it makes sense!

  • Jinx

    I wonder how to register already defined 3rd party module.

  • CodySCarlson

    Dude! Awesome article!!!

    I’ve been trying to find a way to design a ‘Fractal-Routing-Architecture’ using RequireJS — tough to do. I wanted something like:

    $routeProvider.when(‘/some/fractional/route’, {
    —-templateUrl: ‘/app/tmpl/some/fractional/routeView.html’,
    —-controller: firstCallRequireAndReturnTheModuleAt(‘/controllers/some/fractal/routeCtrl’)
    ——–.thenPassItTheSandbox(sandbox)
    ——–.andHereIsTheCallbackForTheRouteSoDoTheUsual
    });

    Still with me? The closest thing I found to help me was the lazy-load plugin from ngModules . org:
    http://ngmodules.org/modules/angular-lazyload
    but it doesn’t seem to allow for passing a sandbox!

    Either way, great article, you’ve even got Ben Nadel commenting on it! Good job! This one’s going in the Exocortex. I’ll be tracking your blog from now on, so don’t hesitate to post if a ‘less-tiresome’ way comes about ;)

  • tracy

    Great article, however, when i download source code from Github and view it on my local machine. There are so many script file cannot be found. Could you give me some suggestion?

  • tishya kaul

    Hi,
    I understand that we are registering the controller with the controllerProvider. However, I do not understand how angular will know that it has to load a certain controller. It would help me figure out whether or not it is necessary for me to mention a controller in the $routeProvider.when() section. Is it not alright to provide the name of the controller to load in the ng-controller property of a page (.html file) only?

  • Wasp Mobile

    Hi When i run the code on my local instance i get this error

    Error: Script error for: angular
    http://requirejs.org/docs/errors.html#scripterror
    var e = new Error(msg + ‘nhttp://requirejs.org/docs/errors.html#’ + id);

    Error: Load timeout for modules: app,angular-route
    http://requirejs.org/docs/errors.html#timeout
    var e = new Error(msg + ‘nhttp://requirejs.org/docs/errors.html#’ + id);
    Error at line 166 require.js

  • Matej

    There’s also angular-couch-potato which does (pretty much) the same thing, however is packaged up into a module so its a bit easier to use..

  • Tim H

    Ify, someone in this comment mentioned couch potato (https://github.com/stu-salsbury/angular-couch-potato)

    have you had a chance to check that out?… or you are sticking with your version of lazy loading? do you still use it nowadays?

  • Sueisfine

    Thanks a lot for the article! Just a heads up: when trying to set it up myself, I noticed that in the “routes.js” file you have the default route as “defaultRoutePath”. But in the “app.js” file you’re using it as “defaultRoutePaths” (plural) which makes it not load the default route as expected.

  • Pedro Justo

    Excellent article!! helped me very much!
    this method can be perfect depending on the app complexity, because one problem that i figured out is that resolve:{deps:function…..} is called everytime you go to the page, and the “resolve:{deps:function…..}” will try to include the script files every time you go to the page! It should only occurs at the first time that the page is visited