Reputation: 1520
I'm following the basic effect pattern of Ngrx using datapersistence.pessimisticUpdate() for a post to the server like so.
@Effect()
myUpdateCompleted$ = this.dataPersistence.pessimisticUpdate(MyActions.UpdateData, {
run: (action: UpdateData, state: MyDataPartialState) => {
return this.myDataService.updateData(action.payload)
.pipe(
map(result => ({
type: MyActions.ReloadData,
payload: result,
})
)
);
},
onError: (action: UpdateData, error) => {
console.error('Error', error);
return new HandleUpdateDataError(error);
}
});
I'd like to reload data after that update is done. However, before I reload the data I'd like to notify the user that the update finished and now a data reload is executing. My intended approach was to dispatch two actions after the update finishes. One action to notify the user (dispatch MyActions.NotifyMessage) and another to reload the data (dispatch MyActions.ReloadData). However, the datapersistence methods only allow for a single action to be returned and no provision for an array of actions to be dispatched. I've tried the solution posted on this question:
Dispatch multiple, ordered, actions from effect in NGRX
But I get the error:
Property 'payload' does not exist on type 'Action'
How do I go about doing this? Should I dump the use of the datapersistence functions and return multiple actions in some other way? If so, how can I do that within an Ngrx Effect? Any help would be highly appreciated.
Upvotes: 1
Views: 3013
Reputation: 11
This work for me:
throwMultipleActions$ = createEffect(() =>
this.actions$.pipe(
ofType(ThrowMultipleActions),
switchMap(({ payload }) => {
const actionsToThrow = [];
payload.forEach(el => {
actionsToThrow.push(attachAction(el));
});
return actionsToThrow
}),
catchError((error) => {
return observableOf(ThrowMultipleActionsFail({ payload: error }));
})
));
const attachAction = (el: { actionName: string; payload: any }) => {
const { actionName, payload } = el;
switch (actionName) {
case 'SetFilter':
return SetFilter({ payload });
case 'GetAllCompanys':
return GetAllCompanys({ payload });
default:
break;
}
};
//Example throwing multiple actions:
this.clientStore.dispatch(
ThrowMultipleActions({
payload: [
{ actionName: 'SetFilter', payload: this.filtros },
{ actionName: 'GetAllCompanys', payload: this.filtros },
],
})
);
Upvotes: 0
Reputation: 1520
This did it.
import { Actions } from '@ngrx/effects';
@Effect()
save$: Observable<Notification | SaveSuccess> = this.actions$
.ofType(MyActions.UpdateData)
.pipe(
switchMap(action => this.myService.save(action.payload)),
switchMap(res => {
return [
new Notification('save success'),
new SaveSuccess(res)
];
})
);
this.actions$
requires import { Actions } from '@ngrx/effects';
In addition to this, if you have to pass data from the original action payload, you'd have to use concatMap like so (Note - the example below just passes the whole action instead of just the payload):
import { Actions } from '@ngrx/effects';
@Effect()
save$: Observable<Notification | SaveSuccess> = this.actions$
.ofType(MyActions.UpdateData)
.pipe(
// The difference is in this switchMap
switchMap(action => {
return this.myService.save(action.payload).pipe(
concatMap<any, UpdateData>(() => of(action))
);
}),
switchMap(origAction => {
return [
new Notification('save success'),
new SaveSuccess(origAction.payload)
];
})
);
Hope this helps anyone struggling with this as I did.
Upvotes: 0
Reputation: 15497
You can use `switchMap for this - Dispatching Multiple Actions from NGRX Effects
@Effect()
save = this.update$.pipe(
map(action => action.payload),
switchMap(payload => this.myService.save(payload)),
switchMap(res => [
new Notification('save success'),
new SaveSuccess(res)
])
);
Upvotes: 2