APP_INITIALIZER – Tapping into Initialization Process in Angular

In this post, we are going to look at how we can use APP_INITIALIZER in Angular. So, what exactly does APP_INITIALIZER do? The best way to answer that is by looking at my previous post, which can be found here. It was about angular environment variables being loaded remotely, instead of environment files which are built into the app.

So, in this scenario, you might need to have access to those variables immediately the app starts. That’s what APP_INITIALIZER allows you to do, provide a function that will be executed during app initialization stage. Angular will allow the functions to be executed to completion before rendering anything.

It even gets better, if it encounters an error, the whole application will not load. This ensure that your remotely loaded configuration are available right from the start. You can use this to load anything you want to during the initialization stage, so it’s available right after the app starts.

To show you how to tap into the initialization process, we are going to use a demo. In this demo, we will look at loading our configurations from the previous post to our angular application. So, without further ado, let’s get started:

Create a New Application

First, Let’s create a brand-new application using Angular CLI.

$ ng new angular-app-initializer-demo-app

And then generate a service to load our configurations:

$  ng generate service config

Next, let’s work on our newly created service to fetch and load our configurations.

Fetching Configurations

One thing to keep in mind before we can go any further, APP_INITIALIZER expects a promise not an observable. Don’t worry, we will still be able to use observables, but our return value must be a promise, otherwise it won’t work. Fortunately for us, RXJS provides a toPromise method to convert that observable to promise.

So, our service is going to need one method for getting configurations:

getConfigs(): Promise<Object> { }

And one property for holding our configurations.

configurations: object = null;

Since we don’t have a backend, we will use RXJS of method to convert a simple array into an observable stream. You can easily fetch data using HTTP Client in Angular, just you normally would under any other service. Next, we are going to pipe to our observable and tap into the observable stream to set the configurations property to the returned value. Then convert the observable stream to a promise and return it.

getConfigs(): Promise<Object> {
  return of(dummyConfigs) // <== this could be a http request here
    .pipe(
      tap(config => {
        this.configurations = config;
      })
    )
    .toPromise();
}

Configuring APP_INITIALIZER

We are going to provide APP_INITIALIZER inside App Module, but this can be done in any other module like CoreModule. Before we can do that, we need to create a function to the method for getting our configuration. The function will accept our config service above, which we shall inject when providing APP_INITIALIZER. It will then call the method to get config and return the resulting promise.

export function loadConfigurations(configService: ConfigServiceService) {
  return () => configService.getConfigs();
}

Next, let’s add our config service and provide APP_INITIALIZER to our list of providers in the App Module. For the APP_INITIALIZER, first we have the provide property, where we indicated we are providing APP_INITIALIZER. Then we indicate we are using factory (useFactory property) and injecting our config service as a dependency for our factory (deps property). We have also added a multi property, which indicates we can have multiple APP_INITIALIZERS and not just the one.

@NgModule({
  declarations: [...],
  imports: [...],
  providers: [
    ConfigServiceService,
    {
      provide: APP_INITIALIZER,
      useFactory: loadConfigurations
      deps: [ConfigServiceService], // dependancy
      multi: true
    }
  ],
  bootstrap: [...]
})

And basically, that’s it. If the promise is resolved successfully, your app should go ahead and load successfully, otherwise it will fail to initialize.

Word of Caution

You can do more complicated stuff but remember that your app won’t start until all sent promises are resolved. So, if you are doing to many things at once, you might impact the performance of your app negatively.

Source Code

You can find the complete source code for this post here.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.