February 20th, 2020
3:15 pm
Using the Angular APP_INITIALIZER

Posted under Angular & Web

This allows the use of asynchronous operations (such as configuration loading) at Angular bootstrap time. It is documented (somewhat minimally to say the least) here.

In my case I needed it to allow early script loading of (in my case Yoti) external scripts at bootstrap time. A Yoti script overwrote some promise code that had already been patched by zone.js earlier. Subsequently, zone.js detected this and the application failed. This is documented here. I also used it to load the app configuration dynamically, rather than from index.html. As well as being a better design due to decoupling from index.html and opening the door to pulling the configuration from an external provider, this also allowed multiple configuration sets to be selectable e.g. from a query string parameter in the url.

This Stack Overflow post shows how to implement the APP_INITIALIZER.  This tutorial post does the same, and goes into details about using multiple providers via a multi provider token. Basically you need to pass a function or a lambda which returns a promise, which completes when your asynchronous operation is done. One point worthy of note is that when rejecting a promise, you need to pass something in the reject, or Angular throws an error stating Cannot read property ‘ngOriginalError’ of undefined.

My implementation is here:

@NgModule({
declarations: [
AppComponent,
FabricComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,

],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
…,
ConfigurationService,
ConfigurationValidator,
ScriptLoader,
PreBootScriptLoader,
ObjectUtils,
{
provide: APP_INITIALIZER,
useFactory: (configurationService: ConfigurationService, preBootScriptLoader: PreBootScriptLoader) => () => {
  return configurationService.load().then(() => preBootScriptLoader.load);
},
deps: [ConfigurationService, ConfigurationValidator, PreBootScriptLoader, ScriptLoader, ObjectUtils],
multi: true
},
],
bootstrap: [AppComponent]
})

Promise rejection code fragment showing passing an error in the reject:

if (this.configurationValidator.validate(appConfig)) {
  console.error(‘Configuration failed validation’, appConfig);
  reject(new Error(‘Configuration failed validation as above.’));
} else {
  resolve();
}

Comments Off on Using the Angular APP_INITIALIZER

Comments are closed.