Amit Sharma
Amit Sharma

Reputation: 758

How to dispatch multiple actions from single effects in NgRx?

My current effect code is like that here is my effect code in which currently i am dispatching single action from effect. But i want to dispatch one more action notificationNew() which i have commented in below effect code.

    bookPropertyRequest$ = createEffect(() => {
    return this.actions$.pipe(
        ofType(ReservationReqActions.bookPropertyRequest),
        concatMap(action =>
            this.ReservationReqService.sendReservationRequest(action.reservationRequest).pipe(
                map(response => {
                    if (response.status) {
                        this.helperService.snackbar('Request Sent.');
                        // Here i want to dispatch another action - notificationNew()
                        return ReservationReqActions.bookPropertyRequestSuccess({ reservationRequest: response.result });
                    } else {
                        const errorCode = response.errorCode;
                        if (errorCode !== null) {
                            this.helperService.errorAlert('', response.message, 'error');
                            return ReservationReqActions.bookPropertyRequestFailure({
                                error: {
                                    type: response.errorCode || null,
                                    message: response.message
                                }
                            });
                        }
                    }
                }),
                catchError(error => EMPTY)
            )
        )
    );
});

Now I want to dispatch another action from action notificationNew() when the above-mentioned effect is success. So my my concern is how we can dispatch multiple actions from single effect.

So how to achieve this?

Upvotes: 3

Views: 3423

Answers (2)

Thierry Falvo
Thierry Falvo

Reputation: 6300

You can use switchMap in place of map operator, to be able to return an array of actions, which will then emit each action :

... 
this.ReservationReqService.sendReservationRequest(action.reservationRequest).pipe(
  switchMap(response => {
    if (response.status) {
      this.helperService.snackbar('Request Sent.');
      return [
        ReservationReqActions.bookPropertyRequestSuccess({ reservationRequest: response.result }),
        UiActions.notificationNew({...})
      ]
...

Suggestion

Here is a proposition of refactoring with less code :

bookPropertyRequest$ = createEffect(() => this.actions$.pipe(
    ofType(ReservationReqActions.bookPropertyRequest),
    concatMap(action =>
      this.reservationReqService.sendReservationRequest(action.reservationRequest).pipe(
        switchMap(response => [
          ReservationReqActions.bookPropertyRequestSuccess({ reservationRequest: response.result }),
          UiActions.notificationNew({...})
        ]),
        catchError(errorResponse => [
          ReservationReqActions.bookPropertyRequestFailure({
            error: errorResponse.error
          }),
          UiActions.errorAlert(errorResponse.error.message);
        ])
      )
    );
  ));

To do that, you need to return the "classic" response with HttpClient inside your sendReservationRequest method:

sendReservationRequest(request: ReservationRequest) {
  return this.httpClient.post(SERVICE_URL);
  // no {observe: 'response'} here
}

Note: Very simple in this example, but maybe in some situation it could be necessary to test errorResponse content inside catchError. To avoid any issue with errorResponse.error.message... Out of topic here.

Upvotes: 6

daddykom
daddykom

Reputation: 220

I solve this kind of problems with an other effect, where i filter for the success Action:

    notificationNew$ = createEffect(() => {
      return this.actions$.pipe(
        ofType(ReservationReqActions.bookPropertyRequestSuccess),
        map((action)=> ReservationReqActions.notificationNew(action.payload) )

So it is clear structured and the code is not too complicated.

Upvotes: 0

Related Questions