typescript - Angular: Cómo implementar correctamente APP_INITIALIZER
Tengo una aplicación Angular 5.2.0. Busqué cómo implementar APP_INITIALIZER para cargar información de configuración antes de que la aplicación se inicie. Aquí un extracto del app.module:
providers: [
ConfigurationService,
{
provide: APP_INITIALIZER,
useFactory: (configService: ConfigurationService) =>
() => configService.loadConfigurationData(),
deps: [ConfigurationService],
multi: true
}
],
Aquí está el configuration.service:
import { Injectable, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Configuration } from './configuration';
@Injectable()
export class ConfigurationService {
private readonly configUrlPath: string = 'Home/Configuration';
private configData: Configuration;
constructor(
private http: HttpClient,
@Inject('BASE_URL') private originUrl: string) { }
loadConfigurationData() {
this.http
.get<Configuration>(`${this.originUrl}${this.configUrlPath}`)
.subscribe(result => {
this.configData = {
test1ServiceUrl: result["test1ServiceUrl"],
test2ServiceUrl: result["test2ServiceUrl"]
}
});
}
get config(): Configuration {
return this.configData;
}
}
Aquí hay un ejemplo de un constructor de un componente donde se utiliza configData:
export class TestComponent {
public test1ServiceUrl: string;
constructor(public configService: ConfigurationService) {
this.test1ServiceUrl = this.configService.config.test1ServiceUrl;
}
}
Funciona bien con todos los componentes que están definidos dentro del <router-outlet></router-outlet>. Pero la misma implementación en un componente fuera del <router-outlet></router-outlet> no funciona.
Cuando depuro el constructor respectivo del componente donde no funciona, dice que configService es null.
¿Por qué se ejecuta el APP_INITIALIZER antes de que se llame al constructor de un componente dentro del <router-outlet></router-outlet>, pero no antes del constructor de un componente fuera del <router-outlet></router-outlet>?
Respuesta #1
Debido a cómo funciona APP_INTIALIZER, se espera que los inicializadores asincrónicos devuelvan promesas, pero tu implementación del multiproveedor de APP_INTIALIZER no lo hace porque la función loadConfigurationData no devuelve nada.
Debería ser algo así:
loadConfigurationData(): Promise<Configuration> {
return this.http.get<Configuration>(`${this.originUrl}${this.configUrlPath}`)
.do(result => {
this.configData = result;
})
.toPromise();
}
Respuesta #2
Haz algo como
export function StartupServiceFactory(startupService: StartupService) {
return () => startupService.load();
}
const APPINIT_PROVIDES = [
StartupService,
{
provide: APP_INITIALIZER,
useFactory: StartupServiceFactory,
deps: [StartupService],
multi: true,
},
];
Servicio de inicio
load():Promise{
return new Promise(resolve, reject){
//load all your configuration
resolve();
}
}
