Dans mon application Angular2, j'essaie de charger des configurations depuis le backend au démarrage avec HTTP afin de pouvoir utiliser les données extraites pour créer des services angulaires.
Chaque fois que j'essaie de lire la réponse HTTP enregistrée dans ma configuration, j'obtiens toujours TypeError: Je ne peux pas lire la propriété 'url' de undefined error.
Il semble que la requête HTTP ne se termine que lorsque la méthode d'amorçage complète est terminée, alors que mon code tente d'extraire la réponse Observable avant qu'elle ne soit récupérée.
Comment puis-je résoudre ce problème pour extraire la configuration du serveur et l'utiliser pour créer des services angulaires au démarrage? (Je veux créer des services au sein de fournisseurs avec des données extraites)
Veuillez commenter s'il existe un meilleur moyen d'extraire la configuration du serveur au démarrage.
Mon main.ts ressemble à ceci:
bootstrap(AppComponent,
[APP_ROUTER_PROVIDERS, HTTP_PROVIDERS, ConfigurationService, Config])
.catch(err => console.error(err)
);
configuration.service.ts
@Injectable()
export class ConfigurationService {
constructor(private http: Http) {
}
load() {
return this.http.get('config/getConfig').map(response => response.json());
}
}
config.ts
@Injectable()
export class Config {
public config;
constructor(public configurationService: ConfigurationService) {
configurationService.load().subscribe(
config => this.config = config,
error => console.error('Error: ' + error)
);
}
get(key: any) {
return this.config[key];
}
}
app.component.ts
@Component({
selector: 'app',
templateUrl: 'app/app.component.html',
styleUrls: ['app/app.component.css'],
directives: [ROUTER_DIRECTIVES],
providers: [MyService]
})
export class AppComponent {
constructor(public myService: MyService) {
}
}
my.service.ts
@Injectable()
export class MyService{
private url;
constructor(public config: Config) {
this.url = config.get('url');
}
}
Vous pouvez utiliser le service APP_INITIALIZER
pour recharger la configuration avant le démarrage de l'application:
bootstrap(AppComponent, [
{
provide: APP_INITIALIZER,
useFactory: (config:Config) => {
return config.load();
},
dependency: [ Config ]
}
]);
Pour cela, vous devez adapter un peu votre classe ConfigService
:
@Injectable()
export class ConfigService {
constructor(private http:Http) {}
load() { // <------
return new Promise((resolve) => {
this.http.get(...).map(res=>res.json())
.subscribe(config => {
this.config = config;
resolve();
});
}
}
Vous pourrez ensuite accéder directement aux propriétés de l'objet de configuration dans votre application.
Lors de l'utilisation de la compilation AoT, une erreur est générée car la fabrique est une fonction anonyme. Ce que vous devez faire ensuite, c'est exporter une fonction pour l'usine
export function ConfigLoader(configService: ConfigService) {
return () => configService.load();
}
et la configuration de l'application ressemble à ceci:
@NgModule({
declarations: [
AppComponent
],
imports: [
HttpModule,
BrowserModule
],
providers: [
ConfigService,
{
provide: APP_INITIALIZER,
useFactory: ConfigLoader,
deps: [ConfigService]
}],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
C'est un meilleur moyen d'écrire la fonction de chargement
public load() {
let promise =this.http.get(url).map(res => res.json()).toPromise();
promise.then(config => this.validation = config);
return promise;
};