Search code examples
rxjsngrxangular-httpclientngrx-effects

ngrx effect - catchError: returning of does not end stream, and the API call does not re-run


I have an effect in NgRX effect, as follows:

$createOrganisation = createEffect(() =>
  this.actions$.pipe(
    ofType(fromOrganisationActions.createOrganisation),
    switchMap((data) => this.organisation.createOrganisation(data)),
    map((response) => fromOrganisationActions.createOrganisationSuccess({ orgId: response.id })),
    catchError((error) => {
      return of(fromOrganisationActions.createOrganisationError(error));
    })
  )
);

However, my stream never seems to end when the catchError is triggered, i.e. in the instance of this.organisation.createOrganisation returning a 400 error.

The action, fromOrganisationActions.createOrganisationError(error) is triggered and my reducer is triggered from this... but if I re-trigger the fromOrganisationActions.createOrganisation effect, this effect runs but the API call is never made a second time.

If I configure it as follows, and dispatch it manually, it works:

$createOrganisation = createEffect(() =>
  this.actions$.pipe(
    ofType(fromOrganisationActions.createOrganisation),
    switchMap((data) => this.organisation.createOrganisation(data)),
    map((response) => fromOrganisationActions.createOrganisationSuccess({ orgId: response.id })),
    catchError((error) => {
      this.store.dispatch(fromOrganisationActions.createOrganisationError(error));
      return throwError(error);
    })
  )
);

But other examples online suggest the first way should work, but it is not for me, and I do not understand why my stream never ends.

Can somebody please advise and tell me why my stream never ends in the first instance?


Solution

  • The catchError should be added to the inner observable.

    $createOrganisation = createEffect(() =>
      this.actions$.pipe(
        ofType(fromOrganisationActions.createOrganisation),
        switchMap((data) => this.organisation.createOrganisation(data).pipe (
          map((response) => 
            fromOrganisationActions.createOrganisationSuccess({ orgId: response.id })),
          catchError((error) => {
            return of(fromOrganisationActions.createOrganisationError(error));
          })
        )),
      )
    );
    

    These mistakes can be caught with eslint-plugin-ngrx, more details about the rule here.