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:
- This seems to be an anti-pattern since I am returning more than one action from the effect (not sure why is that, though)
- Translation effect is somewhat coupled to lots of business-specific actions
- 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())
));