Angular Module Loading

Angular modules, themselves, have the opportunity to configure themselves before the module actually bootstraps and starts to run. We can apply different sets of logic during the bootstrap phase of the app.

Configuration

Angular executes blocks of configuration during the provider registration and configuration phases in the bootstrapping of the module. This phase is the only part of the Angular flow that may be modified before the app starts up.

angular.module('myApp', [])
  .config(function($provide) {
  });

Throughout this book, we use methods that are syntactic sugar around the .config() function and get executed at configuration time. For instance, when we create a factory or a directive on top of the module:

angular.module('myApp', [])
.factory('myFactory', function() {
  var service = {};
  return service;
})
.directive('myDirective', function() {
  return {
    template: '<button>Click me</button>'
  }
})

Angular executes these helper functions at compile time. They are functionally equivalent to:

angular.module('myApp', [])
.config(function($provide, $compileProvider) {
  $provide.factory('myFactory', function() {
    var service = {};
    return service;
  });
  $compileProvider.directive('myDirective',
    function() {
      return {
        template: '<button>Click me</button>'
      }
    })
});

In particular, it’s also important to note that Angular runs these functions in the order in which they are written and registered. That is to say that we cannot inject a provider that has not yet been defined.

The only exception to the rule of in-order definitions is the constant() method. We always place these at the beginning of all configuration blocks.

When writing configuration for a module, it’s important to note that there are only a few types of objects that we can inject into the .config() function: providers and constants. If we inject any old service into a .config() function, then we might accidentally instantiate one before we actually configure it.

The by-product of this strict requirement for configurable services is that we can only inject custom services that are built with the provider() syntax and cannot inject other services.

For more information on how to build with the provider syntax, head over to the services chapter.

These .config() blocks are how we’ll custom configure our own services, such as setting API keys and custom URLs.

We can also define multiple configuration blocks, which are executed in order and allow us to focus our configuration in the different phases of the app.

angular.module('myApp', ['ngRoute'])
.config(function($routeProvider) {
  $routeProvider.when('/', {
    controller: 'WelcomeController',
    template: 'views/welcome.html'
  });
})
.config(function(ConnectionProvider) {
  ConnectionProvider.setApiKey('SOME_API_KEY');
})

The config() function takes a single argument:

configFunction (function)

The function that Angular executes on module load.

In 1.3 and beyond, all .config blocks are run after all .provider blocks have run. This means you can’t use a .config to configure a “downstream” provider. This is a bad practice in any case, but in v1.3+ it simply won’t work.

Run Blocks

Unlike the configuration blocks, run blocks are executed after the injector is created and are the first methods that are executed in any Angular app.

Run blocks are the closest thing in Angular to the main method. The run block is code that is typically hard to unit test and is related to the general app.

Typically, these run blocks are places where we’ll set up event listeners that should happen at the global scale of the app. For example, we’ll use the .run() block to set up listeners for routing events or unauthenticated requests.

Let’s say that we want to run a function that validates that we have an authenticated user every time that we change our route. The only logical place to set this functionality is in the run method:

angular.module('myApp', ['ngRoute'])
.run(function($rootScope, AuthService) { $rootScope.$on('$routeChangeStart',
  function(evt, next, current) {
    // If the user is NOT logged in
    if (!AuthService.userLoggedIn()) {
      if (next.templateUrl === "login.html") {
        // Already heading to the login route so no need to redirect
      } else {
        $location.path('/login');
      }
    }
  });
});

The run() function takes a single argument:

initializeFn (function)

Angular executes this function after it creates the injector.

 
This page is a preview of ng-book.
Get the rest of this chapter plus 600 pages of the best Angular content on the web.

 

Ready to master AngularJS?

  • What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall? Imagine how quickly you could work if you knew the best practices and the best tools?
  • Stop wasting your time searching and have everything you need to be productive in one, well-organized place, with complete examples to get your project up without needing to resort to endless hours of research.
  • You will learn what you need to know to work professionally with ng-book: The Complete Book on AngularJS or get your money back.
Get it now