3

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.

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Had no ideia switchMap even existed. It is working now. Thank you very much.
glad to hear it:)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.