Skip to content
Advertisement

Return Observable From Promise That Gets Rejected

I’m trying to determine how/if I can convert a Promise rejection into a typed Observable.

I have a login component with a function like this…

login() {
  const login$ = this.authenticationService.login(this.loginForm.value)
  login$
  .pipe(
    finalize(() => {
      this.loginForm.markAsPristine();
      this.isLoading = false;
    }),
    untilDestroyed(this)
  )
  .subscribe(
    (credentials) => {
      log.debug(`${credentials.username} successfully logged in`);
      this.router.navigate([this.route.snapshot.queryParams.redirect || '/'], { replaceUrl: true });
    },
    (error) => {
      log.debug(`Login error: ${error}`);
      this.error = error;
    }
  )
}

and an authentication service with a method like this…

login(context: LoginContext): Observable<Credentials> {

  var data = {} as Credentials
  
  // Call a method that returns a Promise
  this.server.authenticate(LoginContext)
  .then((result) -> {
      data.username = result.user.username
      data.token = result.accessToken
      this.credentialsService.setCredentials(data, context.remember)
      // Not sure what to do here...need to return data somehow as an Observable
      // return data
    })
  .catch((err) => {
      // Not sure what to do here either...need to bubble the err up so that it's caught in subscribe
      // return throwError(err)
    })
}

How can I return an Observable<Credentials> if the Promise resolves, and bubble up the error if it rejects?

I know I can make everything work if I change the authentication service function to return Promise<Observable<Credentials>>, which is fine, but for the sake of learning new things I’m trying to figure out if this is possible.

Advertisement

Answer

You can use the from function to convert any Promise to an Observable:

import { from } from 'rxjs';

// ...

class YourClass {
  login(context: LoginContext): Observable<Credentials> {
    return from(this.server.authenticate(LoginContext).then(result => {
      const credentials: Credentials = {
        username: result.user.username,
        token: result.accessToken
      }; 
      this.credentialsService.setCredentials(credentials, context.remember);
      return credentials;
    }));
  }
}
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement