Please ignore variable names and formatting as I've just changed them.
I've been trying to implement RxJS error handling for an observable that takes an action (user click) and then sends the request object from our form and passes that to an HTTP call as you can see below.
Issue: If I send a request (from a form) on our webpage that doesn't exist in the backend, it fails and I get an error back (great!), BUT if I try to resubmit a correct request after my failed attempt, the application just hangs and loads and doesn't do anything.
serivce.ts file
sendRequest$ = this.exampleRatingSubjectAction$.pipe(switchMap(exampleRequest => this.http.post<exampleresponse>(this.PCFUrl + '/example',exampleRequest).pipe(
catchError(this.handleError)
)),
tap(data => console.log(data)),
);
sendExampleRequestEconomy$ = this.exampleSubjectActionEconomy$.pipe(switchMap(exampleRequest=> this.http.post<exampleresponse>(this.PCFUrl + '/example',exampleRequest)
.pipe(
catchError(this.handleError)
)),
tap(data => console.log(data)),
);
private handleError(err: HttpErrorResponse): Observable<never> {
// in a real world app, we may send the server to some remote logging infrastructure
//instead of just logging it to the console
let errorMessage: string;
if (err.error instanceof ErrorEvent) {
// A client-side or network error occured. Handle it accordingly
errorMessage = `An error occured: ${err.error.message}`;
} else {
// The backend returned an unsuccessful response code.
// the resposne body may contain clues as to what went wrong,
errorMessage = `Backend returned code ${err.status}: ${err.message}`;
}
console.error(err);
return throwError(errorMessage);
}
component code:
exampleResponsePriority$ = this.dataService.sendExampleRequest$
.pipe(
map(data => this.exampleResponsePriority = data),
tap(data => {
this.showPageLoader = false;
this.calculatorService.checkMinOrDeficitRate(data);
}),
catchError( err => {
this.showPageLoader = false;
// await this.presentAlert(err);
this.errorMessageSubject.next(err);
console.log("priority")
return EMPTY;
}));
exampleResponseEconomy$ = this.dataService.sendExampleRequestEconomy$
.pipe(
map(data => this.exampleResponseEconomy = data),
catchError( err => {
this.showPageLoader = false;
// await this.presentAlert(err);
this.errorMessageSubject.next(err);
console.log("economy")
return EMPTY;
}));
My only guess is our action stream has already been updated with a request object on the first click, then when the response from the backend is a 500, it's maybe stuck on it and won't allow for a resubmit?
I've tried playing around with updating the action stream on a failed request but couldn't get it to work.
I feel like I'm just a few lines of code away!
Any help would be great.
Problem
It looks like, in your final
catchError(in the component code), you return theEMPTYRxJS stream as the error response. According to the RxJS docs forcatchError:link to documentation, emphasis added.
Your source observer has terminated with an error, so it won't run any of those earlier steps in the pipeline. The subscription going forward will be listening to
EMPTY(doc link), meaning that the subscription handler will never be called (nor will the subscription terminate).Alternative
You may want to try returning the source observable, which is passed to
catchErroras the second argument of the handler. For example, your code might become:Additionally, you may want to look into the docs for the
retryoperator, which can be used instead of (or in conjunction with)catchErrorto achieve similar results.