1

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?

user13067004
  • 131
  • 1
  • 1
  • 5
  • If you debug this, what is the value of `response`? – RJM Feb 09 '21 at 12:57
  • Are you intending to do `return this.markNotificationsAsRead(id)`? That will return the value of your post request to the `fetchData()` method, not the value of your get request. – RJM Feb 09 '21 at 13:02
  • I get an Object with all provided data: Object data: (5) [{…}, {…}, {…}, {…}, {…}] meta: {prev_page: null, current_page: 1, next_page: 2} __proto__: Object – user13067004 Feb 09 '21 at 13:02
  • Is that value of `response` the same in the `switchMap()` AND the `fetchData()` subscribe? – RJM Feb 09 '21 at 13:06
  • "Are you intending to do return this.markNotificationsAsRead(id)? That will return the value of your post request to the fetchData() method, not the value of your get request. – RJM 1 min ago" I want to return data from GET req. – user13067004 Feb 09 '21 at 13:13
  • "Is that value of response the same in the switchMap() AND the fetchData() subscribe? – RJM" Yes. – user13067004 Feb 09 '21 at 13:13
  • What happens if you replace `switchMap()` with `tap()`? – RJM Feb 09 '21 at 13:18
  • It doesn't execute post req. – user13067004 Feb 09 '21 at 13:30
  • Right, I expected that, but is everything in the `fetchData()` working? Do you still get the `RangeError`? Are you getting the notifications data and able to display it etc? – RJM Feb 09 '21 at 13:33
  • Yes, they are displayed now. – user13067004 Feb 09 '21 at 13:36
  • I'll write up an answer that hopefully solves this for you now. – RJM Feb 09 '21 at 13:36

1 Answers1

0

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).

RJM
  • 695
  • 6
  • 12
  • For sure, how can I mark it, tho? I don't have enough reputation to see my upvote :( – user13067004 Feb 09 '21 at 13:56
  • No worries, this link should explain: https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – RJM Feb 09 '21 at 13:57