user11962606
user11962606

Reputation:

What is the best way to use observables for http requests in angular?

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?

Upvotes: 2

Views: 1816

Answers (4)

Martin Paucot
Martin Paucot

Reputation: 1251

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

Upvotes: 3

Ling Vu
Ling Vu

Reputation: 5181

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

Upvotes: 0

Jayme
Jayme

Reputation: 1946

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)
  });

Upvotes: 0

Timothy
Timothy

Reputation: 3593

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

Upvotes: 2

Related Questions