Angular: cómo implementar correctamente APP_INITIALIZER
(1)
Tengo una aplicación
Angular 5.2.0
.
Busqué cómo implementar
APP_INITIALIZER
para cargar la información de configuración antes de que se inicie la aplicación.
Aquí un extracto de
app.module
:
providers: [
ConfigurationService,
{
provide: APP_INITIALIZER,
useFactory: (configService: ConfigurationService) =>
() => configService.loadConfigurationData(),
deps: [ConfigurationService],
multi: true
}
],
Aquí 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 usa
configData
:
export class TestComponent {
public test1ServiceUrl: string;
constructor(public configService: ConfigurationService) {
this.test1ServiceUrl = this.configService.config.test1ServiceUrl;
}
}
Funciona bien con todos los componentes que se definen dentro de
<router-outlet></router-outlet>
.
Pero la misma implementación en un componente fuera de
<router-outlet></router-outlet>
no funciona.
Cuando depuro el respectivo constructor del componente donde no funciona, dice que
configService
es
null
.
¿Por qué se ejecuta
APP_INITIALIZER
antes de que se
APP_INITIALIZER
al constructor de un componente dentro de
<router-outlet></router-outlet>
pero no antes del constructor de un componente fuera de
<router-outlet></router-outlet>
?
Debido a cómo
works
APP_INTIALIZER
, se espera que los inicializadores asíncronos devuelvan promesas, pero su implementación del multiproveedor
APP_INTIALIZER
no lo hace porque la función
loadConfigurationData
no devuelve nada.
Debería ser algo como:
loadConfigurationData(): Promise<Configuration> {
return this.http.get<Configuration>(`${this.originUrl}${this.configUrlPath}`)
.do(result => {
this.configData = result;
})
.toPromise();
}