Reputation: 2072
I'm in the process of learning rxjs and currently facing something I'm not quite sure how to tackle. I need to call multiple API requests, but the issue is that first I need to get a list of names, and then, for each name get the rest of the data. So far I've come up with two map
functions, the first call will get list of names, and the second map
will iterate over the list and call another request to get the rest of the data. I assume this is bad practice but I cannot understand how to use mergeMap
or forkjoin
to achieve a better functioning code.
public getNames(): Observable<any> {
return this.httpClient.get<response>(someUrl)
.pipe(map(res => res.results), map((data)=>{
data.forEach(dat => {
this.getDataByName(dat.name).subscribe(res => {
dat.image = res.image;
});
});
return data;
}));
}
public getDataByName(name): Observable<any> {
return this.httpClient.get<any>(urlToGetMoreDataByName)
.pipe(map(res => res.results));
}
Upvotes: 0
Views: 4134
Reputation: 476
this.campaignService.getCampaignDetailById(this.data.campaignId).subscribe((response: any) => {
if (response && response.data && response.data.length > 0) {
this.campaignService.getCampaignSessionDetailById(response.data[0].session_id).subscribe((response: any) => {
if (response && response.data && response.data.length > 0) {
// second param
this.campaignMockupCatalog = response.data[0]['shrt-campaign-mockup-catalogs'];
let designMockupTypeId = response.data[0]['shrt-campaign-mockup-catalogs'].map((data) => data.design_mockup_type_id);
this.campaignService.getMockupTypes().subscribe((response: any) => {
if (response && response.data && response.data.length > 0) {
let shrtCampMockupType = response.data.find((data) => data.id == designMockupTypeId);
// first param
this.campaignMockupTypes = shrtCampMockupType['shrt-campaign-mockup-type'].map((data) => data);
}
});
}
})
}
})
Upvotes: 0
Reputation: 17762
If I understand right your problem, I would try something along these lines
// remove the specification of the return type (: Observable<any>) since you
// should be able to achieve a more precise result using Typescript
// type inference
public getNames() {
return this.httpClient.get<response>(someUrl).pipe(
map(res => res.results),
// transform "data", which is an array of names in an array of Observables
// this first map is the rxjs map operator
map((data)=> {
// this inner map is the javascript method of the array
// for each dat it returns an Observable which emits when getDataByNme returns
return data.map(dat => this.getDataByName(dat.name).pipe(
// this is an rxjs map operator which retuns a
// dat object with the image property set
map(res => {
dat.image = res.image;
return dat
})
)
)
}),
// concatMap is used here to make sure that we fire the execution of the
// Observable created by forkJoin after the first get operation has returned
concatMap(arrayOfObservables => forkJoin(arrayOfObservables))
);
}
Now getNames
returns an Observable which emits once all the calls to fetch the images have been executed. Using forkJoin
we make sure we launch all the http get operations in parallel. We could use other operators, e.g. `mergeMap, if we wanted to control the concurrency level.
You may find some inspiration about which operators can be possibly used with http operations in this article.
Upvotes: 1