Wednesday, July 23, 2014

Pre-loading data asynchronously in AngularJS before bootstrapping

Suppose you are building an Angular app with login feature. You are using a server-sided framework to build an API that the Angular app consumes. You don't want the server-sided framework to render different pages depending on the user's session status. Instead, you want Angular to check the session status and show/hide certain parts of the page. When the user logs in, the page can respond without a refresh.

Sounds like a plan! But wait, there is one problem. How does Angular know whether the user is logged in before rendering the page?

One option would be to use the server-sided framework to embed session data as globals in the HTML index, so that Angular can take those session data and turn them into appropriate injectable dependencies. But placing session data in a script block on the index just doesn't seem right to me. It results in globals and the data are exposed on the index HTML.

Another option that I adore is to load the session data asynchronously before Angular bootstraps the app. We can guarantee that the data are available and packaged as injectable dependencies when the app bootstraps. All we have to do in the app is to inject the data as dependencies and access them immediately.

Normally, you would place an ng-app on the body or the html tag, to mark the app as an Angular app. Angular would sniff through your HTML, find the ng-app mark, and bootstrap your app once script files are loaded. There is no easy way to sneak in some asynchronously-retrieved data before bootstrapping.

Fortunately, Angular offers us the ability to manually bootstrap our app. This means we can load data asynchronously, and manually bootstrap our app once the data are retrieved. The function that does the manual bootstrapping is angular.bootstrap

To make the data pre-loading process clean and organized, we want to make the data available through dependency injection and not expose them to the global scope. To do this, we can create a pre-load module that contains the pre-loading logic. Pre-loaded data can be registered in another module which can then be injected to the app via module dependency. This Plunker example demonstrates how it works: http://plnkr.co/edit/gwelwkSQyHCroPes4m5e?p=preview

No comments:

Post a Comment