angular – bootstrap asynchronously

This post walks through bootstrapping an angular app asynchronously. You may find yourself needing to bootstrap angular asynchronously if you need to load system wide configs for example.

We’ll cover the following steps to asynchronously boostrap angular:

  • Control when you bootstrap
  • Retrieve data from the server
  • Store data in an angular service
  • Create a loader UI
  • Handle errors

Control when you bootstrap

Ng-app is great for bootstrapping simple apps. However, angular.bootstrap provides more control. So we’ll use angular.boostrap instead of ng-app.

Retrieve data from your server

We should use $http to pull data from our server before bootstrapping. Grabbing $http before we bootstrap is a bit tricky. We’ll use angular.injector to grab $http before bootstrapping.

Store data in an angular service

And we need to store our data somewhere. Storing our data in a service during the configuration block seems as good a place as any. So we’ll create a configServiceProvider and set that object in module.config.

Create a loader UI

While our app is loading, we should show a UI loader. And we want to hide any angular-esq html before our app is bootstrapped.

Handle errors

Finally, we need to handle errors if our data retrieval fails. I’ll leave the implementation up to you. But you should find onFailedToRetriveDataFromServer is a good place to handle your errors.

Put it all together

The code that puts all these concepts together is below. And here’s a jsfiddle.

Javascript

(function () {

  //Create the app, but don't bootstrap it yet.  Bootstrapping
  //will occur after we've loaded the data from our server.
  var createApp = function () {
    var app = angular
      .module("MyApp", [])
      .controller("MyController", function ($scope) {
        $scope.foo = "bar";
      })
      .provider("configService", function () {
        var configService = {
          config : {}
        };
        this.setConfigWithDataFromServer = function (dataFromServer) {
          configService.config = dataFromServer;
        };
        this.$get = function() { return configService; };
      });
    
    return app;
  };

 
  //Fetch the data from our server.  Notice we can access $http
  //by using angular.injector
  var fetchDataFromServer = function() {
    var $http = angular.injector(["ng"]).get("$http");
    return $http.get("http://your.domain.com/yourData");
  };


  //When we're ready we can bootstrap our app and pass in
  //data from our server to the config step for our app
  var bootstrap = function(app, dataFromServer) {
    app
      .config(function (configServiceProvider) {
        //Set up a config service with the data from our server
        //so the rest of the app can acces it
        configServiceProvider.setConfigWithDataFromServer(dataFromServer);
      })
      .run(function (configService) {
        //We can now access configService from anywhere in the app
        console.log("YAY! My config is set with data from my server: " + configService.config);
      });
    
    var $app =  $(".my-app");
    var $loader = $(".my-app-loader");
    $app.removeClass("is-loading");
    $loader.removeClass("is-loading");
    angular.bootstrap($app, ["MyApp"]);
  };
  
  
  //Handle errors if retrieving data from our server failed
  var onFailedToRetriveDataFromServer = function (app, err) {
    console.log("UH OH! Need to handle error.");
  };
  
  
  //Put it all together!
  var initialize = function () {
    var app = createApp();
    fetchDataFromServer().then(
      /*success*/function (dataFromServer) {
        angular.element(document.body).ready(function () { 
          bootstrap(app, dataFromServer); 
        });
      }, 
      /*failure*/function (err) { onFailedToRetriveDataFromServer(app, err); });
  };
  
  initialize();
  
})();

HTML

<div class="my-app is-loading">
  <div ng-controller="MyController">{{::foo}}</div>
</div>
<div class="my-app-loader is-loading">loading</div>

CSS

.my-app.is-loading {
  display: none;
}

.my-app-loader {
  display: none;
}

.my-app-loader.is-loading {
  display: block;
}
Steven Wexler
Follow me!

Steven Wexler

Software Engineer at Hurdlr
I'm a software engineer living in Washington D.C. and working at a startup called Hurdlr. I primarily develop in C#, Javascript, and SQL. And I play around with Python and Scala on the side. I enjoy participating as an active member on StackOverflow and working on side projects.Check out my exceptions.js framework!
Steven Wexler
Follow me!

Leave a Reply