Search code examples
angularrxjsngrxngrx-effects

How do I issue an error in effects from a takeWhile condition?


I have an effect which will do something if the same user is not clicked, to avoid unnecessary requests, correct?

This code works, however when it falls into the condition that the same user that is already clicked, was clicked again, it does not issue any error to the Store, thus not producing any next effect.

How do I return an error if my takeWhile is not satisfied in my logic?

updatePartial$: Observable<Action> = createEffect(() =>
    this.action$.pipe(
        ofType(fromPeopleActions.UPDATE_MANY_PARTIAL),
        withLatestFrom(this.selectorsService.userFriendClicked),
        takeWhile(([action, userFriendClicked]) => action.updates.id !== userFriendClicked.id),
        switchMap(([action, userFriendClicked]) => {
            console.log('oi');
            const peoples: Update<IPeople>[] = [];
            const https: Observable<Update<IPeople>>[] = [];

            peoples.push(action.updates);
            peoples.push({
                ...userFriendClicked,
                changes: {
                    isClicked: false,
                },
            });

            peoples.forEach((people) => https.push(this.backendService.updatePartial(people)));

            return forkJoin(https).pipe(
                map(() => fromPeopleActions.UPDATE_MANY_PARTIAL_SUCCESS({ updates: peoples })),
                catchError((error) => of(fromPeopleActions.UPDATE_MANY_PARTIAL_FAIL({ error: this.requestHandlerService.getError(error) })))
            );
        })
    )
);

Solution

  • Since RxJS 6.4.0, takeWhile takes an optional parameter inclusive that will emit the first item that didn't pass the predicate.

    However in your case instead of the last failed item, you need to throw an error so that it's caught by the catchError operator. One workaround would be to use concatMap before takeWhile for the same condition and throw an error if it fails. Try the following

    updatePartial$: Observable<Action> = createEffect(() =>
      this.action$.pipe(
        ofType(fromPeopleActions.UPDATE_MANY_PARTIAL),
        withLatestFrom(this.selectorsService.userFriendClicked),
        concatMap(([action, userFriendClicked]) => {
          if (action.updates.id !== userFriendClicked.id) {
            return of([action, userFriendClicked]);
          }
          return throwError('Same user clicked');
        }),
        takeWhile(([action, userFriendClicked]) => action.updates.id !== userFriendClicked.id),
        .
        .