Add default property similar to type in construct time of Action

77 Views Asked by At

I would like to create an effect which will be triggered by all success events and throw a success snackbar with a translation related to that action.

I would like to add this translation key to action only once so I don't need to add it while dispatching.

list.action.ts

export const listActions = createActionGroup({
  source: 'List',
  events: {
    'Delete Success': props<{ id: number }>({ translationKey: 'list.delete.success' }),
  }
});

list.effects.ts

actionSuccessful$ = createEffect(
  () => {
    return this.actions$.pipe(
      ofType(listAction.deleteSuccess, detailAction.addSuccess, detailAction.updateSuccess),
      map(({ translationKey }) => this.snackbarService.success({ translationKey }))
    );
  },
  { dispatch: false }
);

Is something like this even possible? Or what would you advise instead of this approach? Also, I would like to prevent adding an effect to each success/fail action separately.

For example action.type is accessible but format of action.type is not very suitable for my translation files.

1

There are 1 best solutions below

0
On

Implementation

Even though there is a way how to do exactly what I want, I just decided on another approach.

How we can add static properties in the construction of action? Simply pass a custom function instead of props method that will return arguments and your static property. For example:

list.actions.ts

export const listActions = createActionGroup({
  source: 'List',
  events: {
    'Delete Success': (response: { id: number }) => ({ ...response, translationKey: 'list.delete.success' }),
  },
});

What I decided

to go with is the default solution with props extended with a general type:

action-extra-metadata.ts

export interface ExtraMetadata {
  translationKey: string;
}

list.actions.ts

export const listActions = createActionGroup({
  source: 'List',
  events: {
    'Delete Success': props<{ id: number } & ExtraMetadata>(),
  },
});

So it means I let the responsibility to write translationKey to the dispatching of action. Most of the time these success / fail actions are dispatched only from one place anyway. And it gives you a bit of variability by changing translation in different situations.

deleteList$ = createEffect(() => {
  return this.actions$.pipe(
    ofType(listActions.delete),
    concatMap(({ withId }) =>
      this.listControllerService.deleteList(withId).pipe(
        map((id: number) => listActions.deleteSuccess({ id, translationKey: 'list.delete.success' })),
        catchError((error) => of(listActions.deleteFailure({ error })))
      )
    )
  );
});

This will blob our effect a bit but it's still possible to store translation keys in a separate file along with store files and import it.