Given the following action:
export const UpsertChartMember = createAction(ClubDetailActionTypes.UPSERT_CHART_MEMBER, props<{ clubId: number, member: IChartMember}>());
I'd like to retrieve the clubId
action parameter in the map
operator to dispatch another action:
@Effect({ dispatch: false })
upsertChartMember = this.actions$.pipe(
ofType(UpsertChartMember),
mergeMap(action => {
const member = action.member;
return this.chartMemberDataService.update(member);
}),
map(member => {
this.messageService.success(this.constService.SAVE_SUCCESS);
this.clubDetailStore.dispatch(UpsertChartMemberSuccess({ member: member }));
// retrieve action.clubId here?! O_o?
// TODO: dispatch here another action based upon action clubId
}),
catchError((error) => {
this.messageService.error(this.constService.SAVE_FAILURE);
this.clubDetailStore.dispatch(UpsertClubChartFailure({ err: error }));
return throwError(error);
}),
);
as alternative I have already in the feature store module the clubId
accessible by a dedicated selector:
export const getCurrentClub$ = createSelector(getclubDetailState$, (state: ClubDetailState) => state.form);
but I don't understand how to combine the selector and the result of ajax call in my effect...
What I am doing wrong?
You can do a switchMap
to grab it from the store using the selector you already have and a combineLatest
to keep pass the member
info forward along with the club
grabbed from the store:
@Effect({ dispatch: false })
upsertChartMember = this.actions$.pipe(
ofType(UpsertChartMember),
mergeMap(action => {
const member = action.member;
return this.chartMemberDataService.update(member);
}),
switchMap(member => combineLatest([
of(member),
this.store.pipe(select(getCurrentClub$)),
])),
map(([member,club]) => {
this.messageService.success(this.constService.SAVE_SUCCESS);
this.clubDetailStore.dispatch(UpsertChartMemberSuccess({ member: member }));
// now you have your club to do whatever you want to
console.log({club});
}),
catchError((error) => {
this.messageService.error(this.constService.SAVE_FAILURE);
this.clubDetailStore.dispatch(UpsertClubChartFailure({ err: error }));
return throwError(error);
}),
);
BTW, the code above can return both the actions directly. By using switchMap
. Instead of map, you can use another chain:
@Effect()
upsertChartMember = this.actions$.pipe(
ofType(UpsertChartMember),
mergeMap(action => {
const member = action.member;
return this.chartMemberDataService.update(member);
}),
switchMap(member => combineLatest([
of(member),
this.store.pipe(select(getCurrentClub$)),
])),
switchMap(([member, club]) => {
this.messageService.success(this.constService.SAVE_SUCCESS);
return [
UpsertChartMemberSuccess({ member: member }),
PutYourOtherActionHere({club...})
];
}),
catchError((error) => {
this.messageService.error(this.constService.SAVE_FAILURE);
this.clubDetailStore.dispatch(UpsertClubChartFailure({ err: error }));
return throwError(error);
}),
);
[Edited by the question author]: Or, by keeping most of your code right as it is:
@Effect({ dispatch: false })
upsertChartMember: any = this.actions$.pipe(
ofType(UpsertChartMember),
mergeMap(action => {
const member = action.member;
let obs: Observable<IChartMember>;
if (member.id > 0) {
obs = this.chartMemberDataService.update(member);
} else {
obs = this.chartMemberDataService.add(member);
}
return combineLatest(of(action), obs);
}),
map((args) => {
this.messageService.success(this.constService.SAVE_SUCCESS);
this.clubDetailStore.dispatch(UpsertChartMemberSuccess({ member: args[1] }));
this.clubDetailStore.dispatch(GetClubOrganizationCharts({clubId: args[0].clubId}));
}),
catchError((error) => {
this.messageService.error(this.constService.SAVE_FAILURE);
this.clubDetailStore.dispatch(UpsertClubChartFailure({ err: error }));
return throwError(error);
}),
);