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
- Both
initializeApp1
&initializeApp2
runs in succession without waiting for each other. initializeApp2
finishes first, although it is invoked afterinitializeApp1
- 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.