Search code examples
angularrxjsrxjs-observablesswitchmapmergemap

Handling two HTTP requests (Angular + RxJS)


This is my first angular project, and I'm still not familiar that well with Observables and RxJS. In my project, at first I want to fetch all notifications with get request. After that, I want to take id of the last notification, so I could send post request to server to mark them all as read. So the code in service looks like this:

 getNotifications(limit: number, page: number): any {
    return this.http
      .get<INotifications>(
        `${API_URL}/notifications?direction=desc&limit=${limit}&order_by=created_at&page=${page}`
      )
      .pipe(
        switchMap((response) => {
          const id = response.data[0].id;
          return this.markNotificationsAsRead(id);
        })
      );
  }

markNotificationsAsRead(id: number) {
    return this.http.post(`${API_URL}/notifications/${id}/mark_all_as_read`, {
      id,
    });
  }

I tried with switchMap and mergeMap

operators, but I get

RangeError: Invalid array length

Code in component:

 fetchData() {
    this.notificationsService.getNotifications(this.limit, this.meta?.next_page || 1).subscribe(
      (response) => {
        this.notifications = [...this.notifications, ...response.data];
        this.meta = response.meta;
        this.isLoading = false;
        // const mostRecentNotification = response.data[0].id;
        // this.markNotificationsAsRead(mostRecentNotification);
      },
      (error) => {
        this.handleErrors(error);
      }
    );
  }

Btw: I can make it work, by deleting this commented section in fetchData function, and just returning get request without piping another operator, but I wanted to give it a try and do it in service. Any ideas why it wont work?


Solution

  • So if I understand correctly, you are trying to get some data (notifications), make a post request when the data comes back, and then display the data in your component.

    The problem you are encountering, is you haven't managed to make the post request from the service and get the data to the component.

    The problem

    The issue as I see it is here:

     switchMap((response) => {
                const id = response.data[0].id;
                return this.markNotificationsAsRead(id);
              })
    

    What this is doing, is return the value of markNotificationsAsRead() to your subscribe not the notifications data that your are expecting.

    The solution

    You are correct in using switchMap() to make two requests in one. I believe all you need is one minor modification:

    switchMap((response) => {
                const id = response.data[0].id;
                return this.markNotificationsAsRead(id).pipe(map(() => response));
              })
    

    By adding the pipe(map(() => response)) you are returning the value of the first observable, while still subscribing to the second (and thus making the post request).