Reputation:
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
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:
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:
Some question references (Thanks to @LingVu):
Upvotes: 3
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
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
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