Sunday, October 12, 2014

AngularJS - Async module loading at Runtime with ocLazyLoad

I finally got to a point in my AngularJS-based app where I'm implementing a "modular" plug-and-play type interface that could eventually grow to consist of integration with dozens of 3rd party applications.  Ideally, each 3rd party integration is its own module (or multiple modules).  Because of the need for scalability, an absolute requirement was that each module could be loaded asynchronously at runtime on an as-needed basis.

Without giving it much upfront thought, and considering the app was already architected in an AMD style using RequireJS, I thought it this would be a no brainer.  Just load the modules at runtime and voila, it would all just work.  That was stupid thinking...  In Angular, every dependency needs to trickle down to the main app module to be loaded prior to the main app instantiation.  In this way, it's not "possible" to load a new module at runtime by pulling down the Javascript at a later point and instantiating it, unless you're open to loading an entirely new sub application.  This is not something I wanted to do.

In comes ocLazyLoad, our savior for asynchronously loading angular js modules, and as luck would have it, it works with RequireJS straight out of the box with one minor configuration update.  Once I stumbled upon this sweet library, things went pretty quick.

Because I am using RequireJS, I am loading my main app with something like this:

angular.bootstrap(document, 'main')

This requires that I do a little bit of configuration to make ocLazyLoad happy.

First off (and this applies to everyone, regardless of use of RequireJS), you need to load the ocLazyLoad library and reference it in your main app module.

For those using requirejs, it might look something like this:

You'll notice two things: A) I reference my "mainApp" module name in the "loadedModules" array, and B) I specify "require" as the asyncLoader.  If you don't use requirejs, you need not have that.

Once this is complete, it's quite easy to load a new module asynchronously:

You'll see in the code above that I have an file called "asyncmodule", this looks like any other module you might create, and contains a directive. Then I have another file called "parentDirective.js". This contains a directive that gets loaded into the "mainApp" module created earlier. It's assumed this directive file would be referenced directly from mainApp.js. As well, this directive lists "$ocLazyLoad" as a dependency so it can be used at run time.

 Inside of the parentDirective, a user clicks a button that invoked a call to the "loadAsyncModule" method. This method then invokes $ocLazy.load() method, passing in the name of the async module and the path to the file. In return, it receives a promise which listens for the successful loading of the module. Once this is complete, you can now use your new module (or directive within the module, as is the case here) as you would any other. In my case, in the success callback of the promise, I then go ahead and load a template dynamically (http://thewebbler.blogspot.com/2014/10/angularjs-be-careful-dynamically.html) that references the "async-directive" as an attribute.  It all works pretty well.

1 comment:

  1. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging…!!..AngularJS 5 Online Training Hyderabad

    ReplyDelete