2

I have got an Angular app that gets data from APIs. So first my code for detail.component.ts looked kind of like this:

//code
getData()
{
this.http.get(url1).subscribe(data1 => 
{/*code: apply certain filter to get a filtered array out*/

this.http.get(url2).subscribe(data2 => 
{/*code: apply certain filter to get a filtered array out*/

this.http.get(url3).subscribe(data3 => 
{/*code: apply certain filter to get a filtered array out*/
})//closing third subscribe form

})//closing second subscribe form
})//closing first subscribe form
}

As you can see, because of nesting all these calls inside each other, the more calls I will have in the future, the messier it all will get. I did some research and got the idea that observables might solve the problem. So I changed the code and this is how it looks like now - data.service.ts:

//code
getData1()
{this.data1 = this.http.get(this.url1)
return this.data1;}

getData2()
{this.data2 = this.http.get(this.url2)
return this.data2;}

getData3()
{this.data3 = this.http.get(this.url3)
return this.data3;}

detail.component.ts:

//code
ngOnInit()
{
this.dataService.getData1().subscribe(data1 => 
{/*code: apply certain filter to get a filtered array out*/

this.dataService.getData2().subscribe(data2 => 
{/*code: apply certain filter to get a filtered array out*/

this.dataService.getData3().subscribe(data3 => 
{/*code: apply certain filter to get a filtered array out*/
})//closing third subscribe form

})//closing second subscribe form
})//closing first subscribe form
}

Data1 must be executed first because Data2 and Data3 need information of the filtered Array from Data1. This is why I struggled to apply solutions like forkJoin. So my question is, if this is a good solution or if you know of a better way to make the code less messy and keep the functionality?

  • so you want to execute data1 first and then you need to execute data2 and data3. Is it fine that data2 and data3 can execute in parallel? – Suhas Parameshwara Dec 13 '19 at 09:05
  • 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) – Ling Vu Dec 13 '19 at 09:19
  • @ng-suhas yes it is fine if data2 and data3 are executed in parallel –  Dec 13 '19 at 09:20
  • I would suggest instead of creating 3 different functions, create one with parameters and pass the necessary info while calling, like getData(url1), getData(url2) and so on. – Piyush Dec 13 '19 at 10:31

4 Answers4

3

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

Some question references (Thanks to @LingVu):

Martin Paucot
  • 1,191
  • 14
  • 30
2

Use switchMap operator to switch between observables...

this.dataService.getData1().pipe(
  switchMap(data1 => {
    // do whatever with data1
    return this.dataService.getData2()
  }),
  tap(data2 => {
    // do whatever with data2
    return this.dataService.getData3()
  })
).subscribe()
Timothy
  • 3,213
  • 2
  • 21
  • 34
0

You could try the async await method

async ngOnInit() {
    const data1 = await this.dataService.getData1().toPromise();
    // apply certain filter to get a filtered array out

    const data2 = await this.dataService.getData2().toPromise();
    // apply certain filter to get a filtered array out

    const data3 = await this.dataService.getData3().toPromise();
    // apply certain filter to get a filtered array out
}

You could also try merge map

this.dataService.getData1()
.pipe(
  map((data1) => {
    // code: filter data here
    return data1;
  }),
  mergeMap((data1) => {
    this.dataService.getData2();
  })
)
.subscribe((finalData) => {
});

Or concatMap

this.dataService.getData1()
  .pipe(
    tap(data1 => console.log(data1)),
    concatMap((data1) => {
      this.dataService.getData2(data1);
    }),
    tap(data2 => console.log(data2)),
    concatMap((data2) => {
      this.dataService.getData3(data2);
    }),
    tap(data3 => console.log(data3)),
  )
  .subscribe(result => {
    console.log(result)
  });
Jayme
  • 1,776
  • 10
  • 28
0

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