0

I have two api calls, one for getting all categories and another to get the posts. In posts api, I'm getting the categories ids, I just need to call the categories and get the categories name and add the name instead of ids in the post calls. I know it's not recommended to use nested api calls, so I used flatMap but have no idea how to implement it.

categories

[
  {
    "id": 5,
    "name": "Angular",
    "slug": "angular",
    "parent": 4
  },
  {
    "id": 4,
    "name": "Tutorial",
    "slug": "tutorial",
    "parent": 0
  }
]

posts

[
  {
    "id": 1,
    "categories": [
      5,
      4
    ]
  },
  {
    "id": 2,
    "categories": [
      5
    ]
  }
]

code

this.blogService.getCategories()
  .pipe(
  flatMap((categories: BlogCategoryModel[]) => {
    console.log(JSON.stringify(categories)); // I think I have to do logic here
    return this.blogService.getPosts();
  })
).subscribe(posts => console.log(JSON.stringify(posts)));

expected result

[
  {
    "id": 1,
    "categories": [
      "Angular",
      "Tutorial"
    ]
  },
  {
    "id": 2,
    "categories": [
      "Angular"
    ]
  }
]
Ranjith Varatharajan
  • 1,596
  • 1
  • 33
  • 76
  • Does this answer your question? [How to do the chain sequence in rxjs](https://stackoverflow.com/questions/37748241/how-to-do-the-chain-sequence-in-rxjs) – R. Richards Dec 13 '19 at 13:14

3 Answers3

1

You can use just forkJoin and no mergeMap/flatMap:

forkJoin([
  this.blogService.getCategories(),
  this.blogService.getPosts(),
]).pipe(
  map(([categories, posts]) => {
    posts.forEach(post => {
      // Replace category ids with their names from `categories` array
    });
    return posts;
  })
).subscribe(posts => ...);

martin
  • 93,354
  • 25
  • 191
  • 226
0

You can use mergeMap

Try like this:

var result = this.blogService.getCategories().pipe(
  mergeMap(value =>  this.getPosts(value[0].id)))
);
Adrita Sharma
  • 21,581
  • 10
  • 69
  • 79
0

Observable can offer a ton of method and tools to create beautiful and readable pipelines. Here is an example :

// my.service.ts
getData1(): Observable {
  return this.httpClient.get();
}

getData2(): Observable {
  return this.httpClient.post();
}

getData3(): Observable {
  return this.httpClient.get();
}
my.component.ts

ngOnInit() {
  this.myService.getData1().pipe(
    map(data => {
      // do what you want with the request answer
      data.id += 1;
      return data;
    }),
    // Pass the modified data and return the Observable for the getData2 request
    switchMap(data => this.myService.getData2(data)),
    // RxJs have a ton of feature to let you play with the data and the pipeline
    // This will wait for 2000ms
    delay(2000),
    // Pass the data returns by getData2 requests to the method getData3
    switchMap(data => this.myService.getData3(data)),
  ).subscribe(
    data => console.log(data); // The result of your pipeline
  )
}

What happen here:

  1. getData1() is call and will return an Observable of our HttpRequest
  2. We modify the result of the request made before (increment the id)
  3. We use the modified result to call getData2 which returns an Observable of the request
  4. We wait 2000ms to continue
  5. We use the result of getData2 request to call getData3
  6. We subscribe to this pipeline to get the final result

If you do not subscribe to a pipeline, it will never be triggered

RxJs is a really huge and nice library to play with data, but too much people do not really not how to use it well.

To use the library you just have one thing to follow:

  • Never put an Observable inside an Observable

About chaining Rxjs, as this is a frequently asked question, you can refer to a number of previously asked questions on SO, among which :

Ling Vu
  • 4,740
  • 5
  • 24
  • 45