Home > Net >  How to trigger multiple effects when translation culture changes in an Angular application?
How to trigger multiple effects when translation culture changes in an Angular application?

Time:11-01

I am working on an Angular 13 application that allows internationalization. When changing the culture, all static resources will instantly be translated, but I need to trigger the reloading of some data because translation is provided by an API.

My code looks like the following.

When the user is changing the current culture, it is stored in the database. This is done using an effect.

public languageChange(value: TranslationLanguage): void {
    this.store.dispatch(UpdatePreferredCultureRequestedAction({ value: value.cultureName }));
    this.translate.use(value.cultureName);
}

updatePreferredCulture$ = createEffect(() => this.actions$.pipe(
    ofType(UpdatePreferredCultureRequestedAction),
    concatMap(action => {
        return this.layoutInfoService.updatePreferredCulture(action.value).pipe(
            catchError(err => {
                this.validation.handleAndDisplayError(err);
                return of(Constants.defaultCultureName);
            })
        );
    }),
    switchMap((culture: string) => {
        return [UpdatePreferredCultureLoadedAction({ value: culture }), 
            QuestionnaireListRequestedAction() // this forces the reloading of some translation-sensitive information
        ];
    }))
);

This only contains only one of the actions that need to be triggered when the translation is changed.

This does the job, but I am not happy with the solution:

  1. This seems to be an anti-pattern since I am returning more than one action from the effect (not sure why is that, though)
  2. Translation effect is somewhat coupled to lots of business-specific actions
  3. Whenever an action to request translatable information is developed, the request action must be included here

Is there a better way to implement effects being triggered when translation culture is changed?

CodePudding user response:

Instead of that effect invoking other effects, I would prefer the other effects to listen to the UpdatePreferredCultureLoadedAction action.

This can be done by adding multiple actions to ofType

foo$ = createEffect(() => 
  this.actions$.pipe(
    ofType(someResource),
    ...
  )
)

Becomes

foo$ = createEffect(() => 
  this.actions$.pipe(
    ofType(someResource, cultureChanged),
    ...
  )
)

CodePudding user response:

timdeschryver's answer convinced me to also try the alternative proposed in the referenced article and define an additional effect handling the UpdatePreferredCultureLoadedAction action. This has the advantage of not messing up with the existing business-related effects, which will become more complex otherwise:

updatePreferredCulture$ = createEffect(() => this.actions$.pipe(
    ofType(UpdatePreferredCultureRequestedAction),
    concatMap(action => {
        return this.layoutInfoService.updatePreferredCulture(action.value).pipe(
            catchError(err => {
                this.validation.handleAndDisplayError(err);
                return of(Constants.defaultCultureName);
            })
        );
    }),
    map((culture: string) =>  UpdatePreferredCultureLoadedAction({ value: culture }))
)); 

questionnaireListRequested$ = createEffect(() => this.actions$.pipe(
    ofType(UpdatePreferredCultureLoadedAction),
    map(_ => QuestionnaireListRequestedAction())
)); 

homeHistoryRequested$ = createEffect(() => this.actions$.pipe(
    ofType(UpdatePreferredCultureLoadedAction),
    map(_ => HistoryQuestionnaireShortListRequestedAction())
));     

historyRequested$ = createEffect(() => this.actions$.pipe(
    ofType(UpdatePreferredCultureLoadedAction),
    map(_ => HistoryQuestionnaireListRequestedAction())
));     
  • Related