Klemme
Klemme

Reputation: 83

Angular2, RxJS Subject http request - On error request wont fire again

I have an issue when receiving an http error response (422 validation error from backend).

Once an http error response is received, I can't fire the request again (on button click).

1) I have a subject property, and I call .next(whatEverDataForTheRequest), in order to kick of the request to the API.

2) In the constructor I subscribe to the subject (.asObservable), and here everything goes fine whenever the response is succesfull, but not when an error happens.

Code is currently like this:

// Properties -> Subject + Observable, used when button is clicked
private saveBookingSubject: Subject<BookingUpdateInterface> = new Subject<BookingUpdateInterface>();
private saveBookingObservable = this.saveBookingSubject.asObservable();

When button is clicked, I create a payload/object and pass in like this:

this.saveBookingSubject.next(payload)

Then in the constructor, I have the following code which gets triggered when .next gets called.

const sub = this.saveBookingObservable.pipe(
  tap(data => {
    this.bookingError = null;
    this.dialogCanClose = false;
  }),
  debounceTime(500),
  switchMap(booking => {
    return this.bookingService.update(booking).pipe(catchError(error => throwError(error)));
  })
).subscribe((response: any) => {
  // This works - Called on success
  console.log('ok', response);
}, (http: HttpErrorResponse) => {
  // This works - Gets called on error
  console.log(http);
});

Successful request works as intended - But when an error is received from backend, then the call to:

this.saveBookingSubject.next(payload)

...is completely ignored, whenever the button gets clicked -> And the subscription logic never kicks in.

What am I missing here? (I do unsubscribe in ngOnDestroy)

Thanks!


EDIT EDIT - WORKING EXAMPLE (as posted by Martin)

const sub = this.saveBookingObservable.pipe(
  debounceTime(500),
  switchMap(booking => {
    return this.bookingService.update(booking).pipe(
      catchError(httpError => {
        this.bookingError = httpError.error.data;
        return of(null);
      })
    );
  }),
  retry(1)
).subscribe((response: any) => {
    // Handle success
  }
});

Upvotes: 2

Views: 918

Answers (1)

martin
martin

Reputation: 96891

The problem you have comes down to "The Observable contract". One chain can emit only one error notification so when your this.bookingService.update emits an error the chain is disposed (unsubscribed). Emitting more next notifications from saveBookingObservable has therefore no effect.

Depending on what you want exactly you want to do it seems like you could just append retry() after switchMap() that will automatically resubscribe.

Upvotes: 4

Related Questions