1

How can I create a ngrx effect which triggers ONLY if both actions complete and return value?

Example: actionASuccess + actionBSuccess -> effect

I tried this solution: How to wait for 2 Actions in @ngrx/effects with combineLatest or ofType(...waitFor) but both do not work as expected.

Here is my code. The content of the switchMap gets called twice but should be called only once:

navigateEmployeeNotificationsTypeSuccess$ = createEffect(() =>
combineLatest([
  this.actions$.pipe(ofType(RouterActions.navigateSuccess)),
  this.actions$.pipe(ofType(RouterActions.navigateEmployeeNotificationsTypeSuccess)),
]).pipe(
  filter(
    ([action1, action2]) =>
      RouterEffects.notNull(action1.success) && RouterEffects.notNull(action2.tab) && RouterEffects.notNull(action2.notificationsType),
  ),
  switchMap(([{ success }, { tab, notificationsType }]) => {
    if (success) {
      // have to set all sections active = false before changing state of the current
      const data = cloneDeep(tab.data);
      data.notificationTypes = data.notificationTypes.map((notificationType: NotificationType) => {
        const active = isEqual(notificationType, notificationsType);
        return {
          ...notificationType,
          active,
        };
      });

      return [
        TabsActions.setTabData({ tab, data }),
        TabsActions.saveCurrentRoute({ url: this.router.url }),
        TabsActions.replaceLastBreadcrumb({ breadcrumb: notificationsType.managerName }),
      ];
    }

    return EMPTY;
  }),
  catchError((error) => of(requestError({ error }))),
),

);

N.Zukowski
  • 600
  • 1
  • 12
  • 31

1 Answers1

0

The thing that i assume is happening is that RouterActions.navigateSuccess is being called multiple times, so the combineLatest will emit value multiple times (given also that RouterActions.navigateEmployeeNotificationsTypeSuccess has emitted single value).

The approach that I will recommend to you is the chain both of those actions with a switchMap operator, otherwise you will end in funny situation whenver you navigate to navigateEmployeeNotificationsTypeSuccess => navigate out => navigate again to navigateEmployeeNotificationsTypeSuccess , in this case you will execute the logic inside the effect even more times.

So my switchMap based approach will look something like the following (assuming that RouterActions.navigateSuccess is being dispatched prior to RouterActions.navigateEmployeeNotificationsTypeSuccess)

navigateEmployeeNotificationsTypeSuccess$ = createEffect(() =>
combineLatest([
  this.actions$.pipe(ofType(RouterActions.navigateSuccess)),
  this.actions$.pipe(ofType(RouterActions.navigateEmployeeNotificationsTypeSuccess)),
])
...

To be

navigateEmployeeNotificationsTypeSuccess$ = createEffect(() =>
this.actions$.pipe(ofType(RouterActions.navigateSuccess)).pipe(
    switchmap(() => this.actions$.pipe(ofType(RouterActions.navigateEmployeeNotificationsTypeSuccess)))
...