Search code examples
angularpromiseobservablechaining

Chaining Observable with Promises for common error handling - Angular


I am writing writing an application using the latest version of the Angular framework. I came across a problem - some of my methods return observables, and some return promises. Is it possible to chain them in order to define a single catch block for all requests in the chain? (I mean the way you would normally do with just promises).

Take a look at this code sample:

loginToBackendServer(token: string) {
return new Promise ((resolve, reject) => {
  this.userService.loginUserWithFb().subscribe(backendUser => {
    this.facebookProvider.getBasicUserData().then(profile => {
      let userData = {
        id: backendUser['id'],
        facebookId: profile['id'],
        picture: profile['picture_large']['data']['url'],
        name: profile['name']
      };
      this.userService.userData = userData;
      this.sharedService.emitUserData(userData);
      this.storage.set("fbAccessToken", token);
      resolve();
    })
      .catch(error => {
        console.log(error);
        reject();
      })
  }, error => {
    console.log(error);
    reject();
  });
});

}

How do I chain the .subscribe() and the .then() so that I only have one catch block instead of having to handle errors separately?

Thanks guys!


Solution

  • You do not need to use a new promise to chain all the response and catch the error in one point. By using fromPromise and concatMap allow you to chain and keep your code organize (Note that I am using the pipeable operators, it is highly recommend to do so).

    import { fromPromise } from 'rxjs/observable/fromPromise';
    import { concatMap } from 'rxjs/operators';
    
    ...
    
    loginToBackendServer(token: string) {
          this.userService.loginUserWithFb().pipe(
              concatMap(backendUser => fromPromise(this.facebookProvider.getBasicUserData()))
          ).subscribe(profile => {
              let userData = {
                  id: backendUser['id'],
                  facebookId: profile['id'],
                  picture: profile['picture_large']['data']['url'],
                  name: profile['name']
              };
    
              this.userService.userData = userData;
              this.sharedService.emitUserData(userData);
              this.storage.set("fbAccessToken", token);
          }, error => {
              console.log(error);
          });
      }