7

If I have a service call that relies on the result of another service call what is the best way to chain them?

myService.getStuffFromServer().subscribe(data => {
  let manipulatedData = functionThatManipulatesData(data);
  myService.getMoreStuffFromServer(manipulatedData).subscribe(moreData => {
    doStuffWithMoreData(moreData);
  });
});

Is the way I have been doing it but the nesting gets a bit messy sometimes. Is there a cleaner way?

HDJEMAI
  • 9,436
  • 46
  • 67
  • 93
Adrian Brand
  • 20,384
  • 4
  • 39
  • 60
  • 1
    tried flatmap ? – Parth Ghiya Jul 07 '17 at 10:16
  • 4
    Possible duplicate of [Angular 2: Two backend service calls on success of first service](https://stackoverflow.com/questions/36712659/angular-2-two-backend-service-calls-on-success-of-first-service) – eko Jul 07 '17 at 10:20

3 Answers3

10

As mentioned in the comments its very simple.

myService.getStuffFromServer().
  .map(functionThatManipulatesData)
  .flatMap(myService.getMoreStuffFromServer)
  .subscribe(doStuffWithMoreData);

map transforms each element of a stream from one type of data to another. But if that transformation involves an asynchronous call we use flatMap.

Most simple way I can describe and this thinking helped me a lot.

We can use flatMap also to add more than one item to the stream. For example , map takes one item and replaces that with new item. What if we want to take one item and add 3 items in its place . For example I want to replace a number with its square and cube too .

----1---2---3--- 

to

----1---1---1---2---4---8---3---9---27----

Then we can use flatMap

stream.flatMap(num => Observable.of(num, num*num, num*num*num));

Now flatMap replaces each element with three new elements. These are two important functionalities of flatmap. Hope I confused you enough :)

Vamshi
  • 9,194
  • 4
  • 38
  • 54
  • This makes sense. Most stuff I have been reading on flatMap just confuses the hell out of me. – Adrian Brand Jul 07 '17 at 10:28
  • 1
    I will add few lines to the answer to confuse you more :P – Vamshi Jul 07 '17 at 10:29
  • You should not answer duplicate questions. – eko Jul 07 '17 at 10:58
  • 1
    Yes, we should not. But sometimes things are so confusing in rx, its so helpful if someone can give working answer readily. That's my perspective . – Vamshi Jul 07 '17 at 11:04
  • 1
    This answer is so much more concise that the convoluted example this has been marked as a duplicate of. – Adrian Brand Jul 07 '17 at 11:33
  • not to mention, sometimes some answers are much more contextual with respect to the OP's question. Yes, underlying concepts maybe a duplicate, but why stop people from answering questions that gives valid, working examples and clear, concise explanation? – CozyAzure Jul 07 '17 at 12:21
  • @CozyAzure https://meta.stackexchange.com/questions/10841/how-should-duplicate-questions-be-handled/ – eko Jul 07 '17 at 13:30
0

For rxjs 6.x.x (tested with 6.5.4), we need to add the pipe() function like this:

myService.getStuffFromServer()
  .pipe(
    map(functionThatManipulatesData), 
    flatMap(manipulatedData =>
        myService.getMoreStuffFromServer(manipulatedData)))
  .subscribe(moreData => {
    doStuffWithMoreData(moreData);
   });

To get it to work correctly.

Vamshi
  • 9,194
  • 4
  • 38
  • 54
HDJEMAI
  • 9,436
  • 46
  • 67
  • 93
-6
myService.getStuffFromServer()
  .subscribe(data => {
     let manipulatedData = functionThatManipulatesData(data);
     return myService.getMoreStuffFromServer(manipulatedData);
  })
  .subscribe(moreData => {
     doStuffWithMoreData(moreData);
  });