Search code examples
angularcordovamodulephonegap

How to get asynchronous data before Angular loads its modules


I'm trying to inject a variable into forRoot({[...]}) method of an Angular module.

I got this variable in an asynchronous way, so I tried to get it before bootstrap Angular. (It comes from cordova.js)

The problem:

It seems that Angular import the modules (and call the 'forRoot' methods) before being bootstrapped.

Is there a way to achieve this ?

Thanks !


An example of what I tried:

app.module.ts

import {NgModule} from '@angular/core';
import {AgmCoreModule} from '@agm/core';

@NgModule({
  imports: [
    AgmCoreModule.forRoot({
      apiKey: window['device'].platform, // value is 'null' instead of 'browser' or something else
      libraries: ['places']
    })
  ],
  // [...]
  bootstrap: [AppComponent]
})

export class AppModule {
}

src/main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

document.addEventListener('deviceready', () => {
  console.log(window['device'].platform); // log 'browser'
  platformBrowserDynamic().bootstrapModule(AppModule)
    .catch(err => console.log(err));
}, false);

/!\ Tips

The library I'm using (@agm/core) expect a string as apiKey, and not a function...


Solution

  • You can use APP_INITIALIZER to provide a factory which will be executed after module imports but before Bootstrap. So you can set the apiKey to any value and override it in the factory: Create a function to fetch die needed data and set the apiKey into the LAZY_MAPS_API_CONFIG Object. The Application bootstrap will continue once all the APP_INITIALIZERS have resolved.

    import { NgModule, APP_INITIALIZER } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { HttpClientModule, HttpClient } from '@angular/common/http';
    import { AgmCoreModule, LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral } from '@agm/core';
    import { AppComponent } from './app.component';
    import { map } from 'rxjs/operators';
    
    export function agmConfigFactory(http: HttpClient, config: LazyMapsAPILoaderConfigLiteral) {
      return () => http.get<{mapsApiKey: string}>("url").pipe(
        map(response => {
            config.apiKey = response.mapsApiKey;
            return response;
        })
      ).toPromise();
    }
    
    @NgModule({
      imports:      [ BrowserModule, HttpClientModule, AgmCoreModule.forRoot({ apiKey: "initialKey"}) ],
      declarations: [ AppComponent ],
      providers: [ {
        provide: APP_INITIALIZER, 
        useFactory: agmConfigFactory, 
        deps: [HttpClient, LAZY_MAPS_API_CONFIG], 
        multi: true} 
        ],
      bootstrap:    [ AppComponent ]
    })
    export class AppModule { }