Search code examples
angulartypescriptreduxngrxngrx-effects

Concatenate 2 Angular NGRX Actions inside an Effect


I am very new to redux and I am facing a problem that I don't know if it is even possible to solve or I should change how the component and store works.

I have a button that, when clicked, dispatches this action:

export const updateOrganizationSettings = createAction(
  '[Organization settings effect] Update organization settings via service',
  props<{ organizationSettings: OrganizationSettings }>()
);

This action triggers the following effect:

updateOrganizationSettings$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(organizationSettingsActionTypes.updateOrganizationSettings),
        concatMap((action) =>
          this.organizationSettingsService.updateOrganizationSettings(
            action.organizationSettings
          )
        )
      ),
    { dispatch: false }
  );

It calls an API that, on success, returns true.

What I want to do is somehow dispatch on success another Action that then changes the store:

export const organizationSettingsUpdated = createAction(
  '[Organization settings reducer] Organization settings updated successfully',
  props<{ updatedOrganizationSettings: OrganizationSettings }>()
);

The problem is that the response from the API is true/false while this action needs the updated model which I have only for the first action.

Is there a way to do it? Is this a bad way to work with the store? I can as a last option change the APIs to return the updated model but I'd like to know if there are other possibilities.

Thanks

=== EDIT ===

This is the API service calling the backend inside the effect:

updateOrganizationSettings(
    organizationSettings: OrganizationSettings
  ): Promise<boolean> {
    return this.httpService
      .put<boolean>('/general-settings', organizationSettings)
      .then((data) => data);
  }

This should be the action that gets dispatched after the api call returns true:

export const organizationSettingsUpdated = createAction(
  '[Organization settings reducer] Organization settings updated successfully',
  props<{ updatedOrganizationSettings: OrganizationSettings }>()
);

And finally this should be the reducer

on(
    organizationSettingsActionTypes.organizationSettingsUpdated,
    (state, action) => ({
      ...state,
      organizationSettings: action.updatedOrganizationSettings
    })
  )

Solution

  • updateOrganizationSettings$ = createEffect(() =>
        this.actions$.pipe(
          ofType(organizationSettingsActionTypes.updateOrganizationSettings),
          mergeMap((action) => {
            return this.organizationSettingsService.updateOrganizationSettings(action.organizationSettings).pipe(
              map(response => updateOrganizationSettingsSuccess(response)) --> the action you are asking for
              catchError(error => updateOrganizationSettingsError(error))
           )
        })
    ));
    

    Ofcourse you should create a updateOrganizationSettingsSuccess and updateOrganizationSettingsError action + hooking it to a reducer.

    Does this help?