Search code examples
rxjsngrxngrx-effects

catch error and emit different action when handling ngrx-effects


In the code snippet below, I want to emit a GetData action if the update operation was successful or a BackendError action if unsuccessful.

@Effect()
updateData$ = this.actions$.pipe(
  ofType(MyActionType.UPDATE_DATA),
  map((action: UpdateData) => action.payload),
  combineLatest(this.authService.getUser(), (myData, user) => this.dataService.updateData(myData, user)),
  map(() => new GetData()),
  catchError((err) => { of(new BackendError(err)))
);

The above code does not seem to be working. Even though the update operation fails due to permission error, the BackendError action is not emitted.

Any help is appreciated.


Solution

  • Your current implementation will swallow errors on the updateData operation, because the action$ (the outer observable) gets mapped to a new GetData() action, regardless of the result of the updateData operation (success or failure).

    In the implementation below, the catchError operator will runif the updateData operation (dataUpdate$ -- the inner observable) throws an error..

    @Effect()
    updateData$ = this.actions$.pipe(
      ofType(MyActionType.UPDATE_DATA),
      mergeMap((action: UpdateData) => {
        const user$ = this.authService.getUser();
        const dataUpdate$ = user$.pipe(
          mergeMap(user => this.dataService.updateData(action.payload, user));
        );
        return dataUpdate$.pipe(
          map(() => new GetData()),
          catchError(err => of(new BackendError(err)))
        );
      })
    );
    

    Additional Resources

    1. Here's some more information on the difference between mergeMap and map.
    2. Official docs for mergeMap.
    3. Example of @Effect using this approach in the @ngrx/effects README.