'How do I actually catch an exception triggered by an NGXS dispatch?

Our project has a system that displays an error modal to the user if an unhandled exception makes its way to the root. (If it matters, this sits in providers: [{provide: ErrorHandler, useClass: OurHandler}] in AppModule’s @NgModule, where OurHandler’s handleError displays the appropriate modal.)

Catching an exception prevents the modal—usually. But for some reason, nothing I do seems to actually catch the exception in the case of an NGXS dispatch.

Some code that works, for background:

@Injectable({ providedIn: 'root' })
class ApiService {

  constructor (private readonly http: HttpClient) {}

  doTheThing(params: Foo): Promise<string> {
    return this.http.post<string>(aUrl, params).toPromise();
  }
}

@State<ThingDoingModel>({ name: 'doing' }) // there's also some defaults here
@Injectable()
export class ThingDoingState {

  constructor (private readonly apiService: ApiService) {}

  @Action(DoTheThing)
  doTheThing(ctx: StateContext<ThingDoingModel>, { foo }: DoTheThing): Promise<string> {
    return this.apiService.doTheThing(foo);
  }
}

@Component({ /*…*/ })
class ThingComponent {

  constructor (private readonly store: Store) {}

  onSubmit() {
    this.store.dispatch(new DoTheThing(this.foo)).subscribe(() => {
      this.showSuccessModal();
    });
  }
}

This all works perfectly—so long as doing the thing is successful. However, sometimes the POST might get an error response. So I want to catch that, and call this.showErrorModal(error.message). That isn’t hard either—but no matter what I do, the exception keeps bubbling up so I also get our default unhandled error modal.

Things I’ve tried:

  onSubmit() {
    this.store.dispatch(new DoTheThing(this.foo))
      .pipe(
        catchError(err => {
          this.showErrorModal(err.message);
          return EMPTY;
        }),
      )
      .subscribe(() => {
        this.showSuccessModal();
      });
  }
  onSubmit() {
    try {
      this.store.dispatch(new DoTheThing(this.foo)).subscribe(() => {
        this.showSuccessModal();
      });
    }
    catch (err) {
      this.showErrorModal(err.message);
    }
  }
  onSubmit() {
    this.store.dispatch(new DoTheThing(this.foo)).toPromise()
      .then(() => {
        this.showSuccessModal();
      })
      .catch(err => {
        this.showErrorModal(err.message);
      });
  }

But none of these actually catch the exception thrown when the HttpClient gets a 500 response. They mostly work—the actual try/catch version didn’t display the error modal I wanted, but the others did—but in all of these I also get the second modal that I do not want.

So how and/or where do I actually catch this exception?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source