NashTech Insights

Angular How to use APP_INITIALIZER

Picture of Alka Vats
Alka Vats
Table of Contents

In this blog, we look at what APP_INITIALIZER is and how to use it in Angular applications. We will show you how to use it by creating an example app.

If you want to learn about a new feature of angular, you can refer here.

What is APP_INITIALIZER

The APP_INITIALIZER is an instance of InjectionToken. It is a built-in Injection token provided by Angular.

Angular will execute the function provided by this token when the application loads. If the function returns the promise, then the angular will wait until the promise is resolved. This will make it an ideal place to perform some initialization logic before the application is initialized.

Dependency Injection

The Angular injector uses the DI token to locate the dependencies in the Angular Provider. We register the dependency in the provider using the token

providers :[{ provide: token, useClass: SomeService }]

Thetoken can be either type, a string or an instance of InjectionToken.

The type-token
providers :[{ provide: productService, useClass: productService}]
The string token
providers :[ {provide:'MESSAGE', useValue: 'Hello Angular'}]
The InjectionToken

The InjectionToken is used whenever the type that is being used does not have runtime representation such as when injecting an interface, callable type,array, etc

export const MESSAGE = new InjectionToken<string>('Hello Angular'); 
 
providers :[ { provide: HELLO_MESSAGE, useValue: 'Hello World!' }];

Where to use APP_INITIALIZER

As mentioned earlier, the APP_INITIALIZER is run when the application is initialized. The Angular suspends the app initialization until all the functions provided by the APP_INITIALIZER are run. If any of those initializers return a promise, then the angular waits for it to resolve, before continuing with the App initialization

This gives us an opportunity to hook into the initialization process and run some of our application’s custom logic. You can load runtime configuration information. load important data from the backend etc.

APP_INITIALIZER Example

Create a new Angular Project

Create app-init.service.ts under the folder src/app.

import { Injectable }  from '@angular/core';
 
@Injectable()
export class AppInitService {
 
    constructor() {
    }
    
    Init() {
 
        return new Promise<void>((resolve, reject) => {
            console.log("AppInitService.init() called");
            ////do your initialisation stuff here  
            setTimeout(() => {
                console.log('AppInitService Finished');
                resolve();
            }, 6000);
 
        });
    }
}

This is a simple service, which has one method Init. The method returns a Promise.

return new Promise<void>((resolve, reject) => {

Inside the method, we have set up a timer that waits for 6000 milliseconds and then calls the resolve

Open the app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
 
import { AppRoutingModule } from './app-routing.module';
 
import { AppComponent } from './app.component';
import { AboutUsComponent } from './about-us.component';
import { HomeComponent } from './home.component';
import { ContactUsComponent } from './contact-us.component';
 
import { AppInitService } from './app-init.service';
 
export function initializeApp1(appInitService: AppInitService) {
  return (): Promise<any> => { 
    return appInitService.Init();
  }
}
 
@NgModule({
  declarations: [
    AppComponent, AboutUsComponent,HomeComponent,ContactUsComponent
  ],
  imports: [
    HttpClientModule,
    BrowserModule,
    AppRoutingModule,
  ],
  providers: [ 
    AppInitService,
    { provide: APP_INITIALIZER,useFactory: initializeApp1, deps: [AppInitService], multi: true}
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

First, we need to import APP_INITIALIZER from the @angular/core

import { NgModule, APP_INITIALIZER } from '@angular/core';

We need to execute the appInitService.Init(). We cannot do it directly from the provider. Needs to create a function that invokes the appInitService.Init() and returns a Promise. We do that in initializeApp1 function.

import { AppInitService } from './app-init.service';
 export function initializeApp1(appInitService: AppInitService) {  return (): Promise<any> => {     return appInitService.Init();  }}

Finally,. use the APP_INITIALIZER token to provide the initializeApp1

  providers: [ 
    AppInitService,
    { provide: APP_INITIALIZER,useFactory: initializeApp1, deps: [AppInitService], multi: true}
  ],
 

The useFactory is used because initializeApp1 is a function and not a class. The Angular Injector executes this function, which in turn calls the appInitService.Init().

The useFactory is used because initializeApp1 is a function and not a class. The Angular Injector executes this function, which in turn calls the appInitService.Init().

The Angular-Dependency injection injects dependencies to classes & components, but not to functions. But our initializeApp1 is a function and needs AppInitService to be injected as the argument. We do that by using the deps: flag and let angular know that it needs to create an instance of AppInitService and inject it to the initializeApp1 function.

The multi : true creates the multi-provider DI token. This means that you can provide an array of providers for a DI token.

If multi: false (which is the default) is set and uses a token more than once, the last to register will override all the previous tokens. i.e. you can have only one provider for token.

If multi: true is set, then the new providers are added to the previously registered providers making it more than one provider for a token. The angular will execute all of them when the token is invoked.

Run the app & Open the Chrome developer console. You will see that the messages from the service appear first, before the “Angular running in development mode” message.

If you return reject from the service, the angular app will not start.

The Observables are not yet supported in APP_INITIALIZER

Multi Providers in APP_INITIALIZER

You can use the multi: true to create Multi Provider token. This means we can create more than one function/service and invoke it during initialization.

Create another factory function initializeApp2, which just writes to the console after a timeout of 2000 milliseconds.

export function initializeApp2() {
  return (): Promise<any> => {
    return new Promise((resolve, reject) => {
      console.log(`initializeApp2 called`);
      setTimeout(() => {
        console.log(`initializeApp2 Finished`);
        resolve();
      }, 2000);
    });
  };
}

Next, register it with the APP_INITIALIZER token as shown below.

  providers: [ 
    AppInitService,
    { provide: APP_INITIALIZER,useFactory: initializeApp1, deps: [AppInitService], multi: true},
    { provide: APP_INITIALIZER,useFactory: initializeApp2, multi: true}
  ],

Run the app. You will observe the following

  1. Both initializeApp1 & initializeApp2 runs in succession without waiting for each other.
  2. initializeApp2 finishes first, although it is invoked after initializeApp1
  3. The Angular waits for both functions to finish

Summary

The APP_INITIALIZER is an instance of InjectionToken. It allows us to hook into the Angular Initialization process and run our custom logic like retrieving some important data

Finally, for more such posts, please follow our LinkedIn page- FrontEnd Competency.

Picture of Alka Vats

Alka Vats

Alka Vats is a Software Consultant at Nashtech. She is passionate about web development. She is recognized as a good team player, a dedicated and responsible professional, and a technology enthusiast. She is a quick learner & curious to learn new technologies. Her hobbies include reading books, watching movies, and traveling.

Leave a Comment

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

Suggested Article