Search code examples
angularngrxangularfire

NgRx effect only listens to last returned observable, ignores any previous returned observable


I'm syncing my app to firestore, listening for changes. When the app starts, it immediately dispatches a couple of actions to my store, to add the documents. I also have a NgRx effect waiting for the add action to be triggered to execute some code, mainly fetching other 2 documents from the references on the document dispatched with the action. I return a forkJoin and the effect only completes the last returned observable, ignoring all past ones.

I have already tried many RxJs operators to debounce, merge, and so on but it has the same result.

The service responsible for syncing the documents

fStore.collection<ReservationDocument>('reservations', query =>
            query.where('hotel', '==', hotel.ref)
          )
          .stateChanges()
          .subscribe(actions => {
            actions.forEach(action => {
              switch (action.type) {
                case 'added':
                  console.log(action.payload);
                  store.dispatch(AddReservation({ reservation: action.payload }));
                  break;
                case 'modified':
                  store.dispatch(ModifiyReservation({ reservation: action.payload }));
                  break;
                case 'removed':
                  store.dispatch(RemoveReservation({ reservation: action.payload }));
                  break;
              }
            });
          });

And the effect

getClientAndHotel$ = createEffect(() =>
    this.actions$.pipe(
      ofType(ADD_RESERVATION),
      switchMap(
        (addReservation: {
          reservation: DocumentChange<ReservationDocument>;
        }) => {
          console.log('hello');
          return forkJoin([
            (addReservation.reservation.doc.get(
              'client'
            ) as DocumentReference).get(),
            (addReservation.reservation.doc.get(
              'hotel'
            ) as DocumentReference).get()
          ]).pipe(
            map(
              result => {
                console.log(addReservation.reservation.doc.ref.path);
                return {
                  type: UPDATE_RESERVATION,
                  client: ClientFromDocumentData(
                    result[0].data() as ClientDocument,
                    result[0].ref
                  ),
                  hotel: HotelFromDocumentData(
                    result[1].data() as HotelDocument,
                    result[1].ref
                  ),
                  reservation: addReservation.reservation
                };
              }
            )
          );
        }
      )
    )
  );

I expect for forkJoin made to complete and dispatch an action, however, no matter how many times the effect was triggered, only the last trigger will dispatch the action. I suspect it simply overwrites the subscription every time the effect gets triggered, without waiting for the previous one to complete but I have no idea how to solve this issue.


Solution

  • As the comment on this questions mentions, you should use mergeMap instead of switchMap.

    switchMap will cancel a pending request, while mergeMap will handle all requests. If the order of requests matters, use concatMap.

    https://rxjs-dev.firebaseapp.com/api/operators/mergeMap

    https://rxjs-dev.firebaseapp.com/api/operators/switchMap

    https://rxjs-dev.firebaseapp.com/api/operators/concatMap