Reputation: 268
APP_INITIALIZER runs a series of nested promises (I've tried subscribes with no difference in the result).
The APP_INITIALIZER needs to get authenticated before it goes to retrieve data from the API server. It also needs to pull two tables from the API server (in sequence).
In api.service, http/get authorization happen in a promise. After the promise (then), I go to get data from the API service.
The issue is the component ngOnInit() - It attempts to get the variables before they exist.
I have tried the following code in the component, but all that does is call the initData() twice.
this.people = await this.apiService.initData();
api.service:
async initData(): Promise<Person[]> {
this.userData$ = this.http.get('/.auth/me', {observe: 'response'});
this.userData$.toPromise().then( res => {
this.resBody = res.body;
this.token = res.body[0].access_token;
this.getLegalSub(this.legalsubdeptsURL)
.toPromise().then(legalsubdepts => {
this.legalsubdepts = legalsubdepts;
this.getPeopleData(this.personURL)
.toPromise().then(people => {
this.people = people;
return this.people;
});
});
});
}
return this.people;
}
app.module
export function initData(appInitService: APIService) {
return (): Promise<any> => {
return appInitService.initData();
}
}
...
providers: [
APIService,
{ provide: APP_INITIALIZER, useFactory: initData, deps: [APIService], multi: true }
],
the component that runs before APP_INITIALIZER is done
ngOnInit() {
this.people = this.apiService.people;
this.userName = this.apiService.userName;
console.log("username");
console.log(this.userName);
}
I need to get the authorization before I can get data from the API server. I then need the data from the API server before I process the component.
I eventually get data, but not in time for the component.
Upvotes: 5
Views: 10622
Reputation: 268
The Answer:
in api.service - initData() needs to return a Promise. The code goes on too far.
initAuth(): Promise<any> {
this.userData$ = this.http.get('/.auth/me', {observe: 'response'});
return this.userData$.toPromise()
}
initLegalSub(): Promise<any[]> {
this.initAuth().then( res => {
this.resBody = res.body;
this.legalSub$ = this.getLegalSub(this.legalsubdeptsURL).toPromise();
});
return this.legalSub$;
}
initPeople(): Promise<Person[]> {
this.initAuth().then( res => {
this.resBody = res.body;
this.people$ = this.getPeopleData(this.personURL).toPromise();
});
return this.people$;
}
You'll notice both initLegalSub() and initPeople() call initAuth() - to get the authentication BEFORE they attempt to get data.
THEN, both of these return Promise data - that is used in people.component.
constructor( private apiService: APIService ) {
this.legalSub$ = this.apiService.initLegalSub();
this.people$ = this.apiService.initPeople();
}
The initialization of the data happens in the app.module
providers: [
APIService,
{ provide: APP_INITIALIZER, useFactory: initPeople, deps: [APIService], multi: true },
{ provide: APP_INITIALIZER, useFactory: initLegalSub, deps: [APIService], multi: true }],
I should put in more logic to determine what to do IF the promise fails, but for now, this allows multiple initializers to happen asynchronously.
Upvotes: 0
Reputation: 8040
APP_INITIALIZER
is a callback is invoked before an app is initialized. All registered initializers can optionally return a Promise. All initializer functions that return Promises must be resolved before the application is bootstrapped.
In your case, you return a promise but it resolves almost immediately because you do not wait for the response to be finished. You should wait for your promises and you can do this by means of await
directive
async initData(): Promise<Person[]> {
this.userData$ = this.http.get('/.auth/me', {observe: 'response'});
await this.userData$.toPromise().then(async res => {
this.resBody = res.body;
this.token = res.body[0].access_token;
return await this.getLegalSub(this.legalsubdeptsURL)
.toPromise().then(async legalsubdepts => {
this.legalsubdepts = legalsubdepts;
return await this.getPeopleData(this.personURL)
.toPromise().then(people => {
this.people = people;
return this.people;
});
});
});
}
return this.people;
}
Upvotes: 7