Reputation: 413
I need to wait for two of my nested Observables to be completed before navigating to another page. I don't know what is the best way to do this since they are nested, therefore I'm having sync problems in my Angular app. The Observables are being set at my authentication service. authentication.service.ts:
login(username: string, password: string) {
let reqUrl = AppSettings.__USER_TOKEN_URL;
let reqHeaders = this.authConfig.token.headers;
let reqBody = encodeURI(
this.authConfig.token.body
.replace(/{{ username }}/g, username)
.replace(/{{ password }}/g, password));
//
// Get token, then get user identity, if login successfull.
//
return this.http.post(reqUrl, reqBody, reqHeaders)
.map((response) => this.getIdentity(response))
.catch(this.handleErr);
}
private getIdentity(response: Response) {
//
// Get user identity based on token.
//
let body = response.json();
let token = body.access_token;
if (null != token && undefined != token) {
this.authConfig
.identity
.headers
.headers.set('authorization', 'Bearer ' + token);
let reqUrl = AppSettings.__USER_IDENTITY_URL
let reqHeaders = this.authConfig.identity.headers;
let reqbody = this.authConfig.identity.body;
return this.http.post(reqUrl, reqbody, reqHeaders)
.map((response) => this.setUser(response))
.catch(this.handleErr)
.subscribe();
}
}
Then at my Login component, I'm trying to call the service login() method, and when it is finished, I want to navigate to another instance. login.component.ts:
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password).subscribe(
data => { },
error => { console.log('Error authenticating: ' + error); },
() => { this.router.navigate([this.returnUrl]) });
}
But it's not working. The Observables are still running when router.navigate
is triggered.
Any ideas for an Angular rookie?
Thanks in advance.
Upvotes: 3
Views: 1161
Reputation: 29635
The problem is you are simply calling subscribe
inside getIdentity()
which doesn't make the two observables sequential.
Instead, you need to return the observable and not the subscription object there and use switchMap
.
getIdentity:
private getIdentity(response: Response) {
//
// Get user identity based on token.
//
let body = response.json();
let token = body.access_token;
if (null != token && undefined != token) {
this.authConfig
.identity
.headers
.headers.set('authorization', 'Bearer ' + token);
let reqUrl = AppSettings.__USER_IDENTITY_URL
let reqHeaders = this.authConfig.identity.headers;
let reqbody = this.authConfig.identity.body;
return this.http.post(reqUrl, reqbody, reqHeaders)
.map((response) => this.setUser(response))//return observable.
}
}
In the login call:
return this.http.post(reqUrl, reqBody, reqHeaders)
.switchMap((response) => this.getIdentity(response))
.catch(this.handleErr);
The switchMap
will switch to the second observable and return it on completion of the first.
Upvotes: 0