In This tutorial, we look what is APP_INITIALIZER
is and how to use in Angular applications. We will show you how to use it by creating an example app.
Table of Contents
What is APP_INITIALIZER
The APP_INITIALIZER
is an instance of InjectionToken
. It is a built in Injection token provided by Angular.
The 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 ideal place to perform some initialization logic before the application is initialized.
Dependency Injection Recap
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
1 2 3 | providers :[{ provide: token, useClass: SomeService }] |
The token
can be either type
, a string
or an instance of InjectionToken
.
The type token
1 2 3 | providers :[{ provide: productService, useClass: productService}] |
The string token
1 2 3 | 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
1 2 3 4 5 | 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 intializers 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 our application 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
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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
.
1 2 3 | return new Promise<void>((resolve, reject) => { |
Inside the method we have setup a timer which waits for 6000 milliseconds and then calls the resolve
Open the app.module.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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
1 2 3 | import { NgModule, APP_INITIALIZER } from '@angular/core'; |
We need to execute the appInitService.Init()
. We cannot do it directly from the provider. We need to create a function which invokes the appInitService.Init()
and returns a Promise
. We do that in initializeApp1
function.
1 2 3 4 5 6 7 8 9 | 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
1 2 3 4 5 6 | 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 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 a instance of AppInitService
and inject it to the initializeApp1
function.
The multi : true
creates the multi provider DI token. Which means that you can provide array of providers for a DI token.
If multi: false
(which is default) is set and use 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 in invoked.
The run the app & Open the Chrome developer console. You will see that the messages from the service appears 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 console after a timeout of 2000 milliseconds.
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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.
1 2 3 4 5 6 7 | 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 the functions to finish
Suggested Readings
Angular Services
Angular Dependency Injection
Angular Injector, @Injectable & @Inject
Angular Providers
Hierarchical Dependency Injection
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
Great post! I really appreciate the clear examples you provided for using APP_INITIALIZER in Angular. It’s a powerful feature, and your explanation made it easy to understand how to implement it in my own projects. Thank you for sharing!
what is deps property inside provider obj? why it is required?
Thank u very much!
How to deal with promise and timeouts in an app_initialzer? Because it’s blocking the whole app, isn’t it?
You may take a look at this stackoverflow question
https://stackoverflow.com/questions/48564687/how-to-handle-inform-users-about-unrecoverable-exceptions-in-an-app-initializer/56021193#56021193
Also this
https://github.com/angular/angular/issues/21252
very helpful, thankyou!
Thanks a lot. this topic was really helpful.
I like it
Excellent post. Thanks you very much
Thank you a million times over! This really saved me.
Is It possible to run one APP_INITIALIZER before others? That initializeApp2 and initializeApp3 wait for initializeApp1 to finish before they start running?
Please take a look at
https://medium.com/@gmurop/managing-dependencies-among-app-initializers-in-angular-652be4afce6f
Thanks to share your knowledges, your article was useful and helps me to understand how the APP_INIZIALIZER works
Thanks!!!
you saved my life 😛 thx