简体   繁体   中英

How to nicely throw an error to an Angular RXJS Observable subscriber

For the function below, how can I throw an error from the 'BROKEN' like that can be handled nicely by its subscriber in the same way as the 'WORKS' line of code?

What I'm seeing is that the 'Works' line passes the error neatly this function's subscriber, whereas the BROKEN line just blows up without getting handled by its subscriber. I'm using Angular (version 5.0.3) in an Ionic project, RXJS version 5.5.2, and the HttpClient in @angular/common/http.

public makeRequest(requestParameters) {

  return Observable.create(observer => {

    let url = 'http://example.com/service/action?a=b';

    this.http.get(url,{withCredentials: true})
      .subscribe(data => {
        if(data["success"] !== true)
          observer.error("Unexpected result");//BROKEN
        else
          observer.next(data["payload"]);
      },
      err => {
        console.log('error: ' + err);
        observer.error(err);//WORKS
      });
    });
}

Here's an example of a function that calls the one above:

public getStuffFromServer(){
  this.makeRequest({parameters go here}).subscribe(
      data => {
        //do something with the results
      },
      err => {
        //This never gets called from the 'BROKEN' code (but it does from the WORKS code
      }
    );
}

Thanks for your help!

So the problem seems to be that in the line:

if(data["success"] !== true)
    observer.error("Unexpected result");//BROKEN`

The subscription at this point hasn't experienced an error, in fact the subscription has returned data.

Try:

 observer.next(false);

Or something similar.

OK, it looks like I found the answer on this page: https://codingblast.com/rxjs-error-handling/

The key is to use the map and catch functions like so:

public makeRequest(requestParameters) {

return Observable.create(observer => {
let url = 'http://example.com/service/action?a=b';
this.http.get(url,{withCredentials: true})
  .map(data => {
    if(data["success"] !== true)
      throw new Error("Something meaningful");
    return data["payload"];
   })
  .catch(err => {
    return Rx.Observable.throw(err);
   });
  .subscribe(data => {
      observer.next(data);
  },
  err => {
    console.log('error: ' + err);
    observer.error(err);
  });
});
}

Hopefully this will help somebody. Thank you everyone who answered or gave it some thought!

Here is a complete working example how to get internet connection for both, device and browser. Using Angular 7 and RxJs 6.3.3:

The service:

import {
  Injectable
} from '@angular/core';
import {
  Network
} from '@ionic-native/network';

import {
  Platform
} from 'ionic-angular';

import {
  Observable,
  fromEvent,
  merge,
  of
} from 'rxjs';

import {
  mapTo
} from 'rxjs/operators';

@Injectable()
export class NetworkService {

  private online$: Observable < boolean > = null;

  constructor(private network: Network, private platform: Platform) {
    this.online$ = Observable.create(observer => {
      observer.next(true);
    }).pipe(mapTo(true));
    if (this.platform.is('cordova')) {
      // on Device
      this.online$ = merge(
        this.network.onConnect().pipe(mapTo(true)),
        this.network.onDisconnect().pipe(mapTo(false)));
    } else {
      // on Browser
      this.online$ = merge( of (navigator.onLine),
        fromEvent(window, 'online').pipe(mapTo(true)),
        fromEvent(window, 'offline').pipe(mapTo(false))
      );
    }
  }

  public getNetworkType(): string {
    return this.network.type
  }

  public getNetworkStatus(): Observable < boolean > {
    return this.online$;
  }

}

Wherever you need to check just import the service and use just like this:

...
    this.networkService.getNetworkStatus().subscribe((isConnected: boolean) => {
     console.log('Is it connected? '+isConnected);
    });
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM