I am putting together an application that displays information about 'Modyules' (on a course) that it has to pull via two http.gets (I have no control over the apis unfortunately):
- Gets the list of Modyule.ids - need to store the id
- For each Modyule.id another http.get to get the Modyule.name
In my modyule.component.ts, I have:
this.modyuleService.getModyules()
.subscribe(
modyules => this.modyules = modyules,
error => this.errorMessage = <any>error
);
In my modyule.service.ts, I have:
getModyules (): Observable<Modyule[]> {
return this.http.get(listOfModyuleIdsUrl + '.json')
.map(this.getModyulesDetails)
.catch(this.handleError);
}
But the getModyuleDetails is where I am struggling. This is where I have got to so far, mainly based on:
http://www.syntaxsuccess.com/viewarticle/angular-2.0-and-http
and looking at, but not seeing how I can apply:
https://stackoverflow.com/a/35676917/2235210
private getModyulesDetails = (res: Response) => { // instance method for defining function so that the this.http below refers to the class.
let listOfModyules = res.json();
let modyulesToReturn = [];
for (let individualModyule of listOfModyules){
let tempModyule = new Modyule;
tempModyule.id = individualModyule.id;
this.http.get(individualModyuleUrl + individualModyule.id + '.json')
.map((res: Response) => res.json()))
.subscribe(res => {
tempModyule.name = res.name
modyulesToReturn.push(tempModyule);
});
}
return modyulesToReturn;
}
Now this is working on my local machine where I have mocked up the .json responses as static .json files..but, when I'm dealing with the real api, I can't rely on the http.gets in the for loop to have completed before returning modyulesToReturn.
I've had a couple of attempts at forkJoin but don't see how I can combine this with the requirement to capture the Modyule.id from the first http.get.
I'd be very grateful for any pointers for how to do parallel requests which depend on an initial request and yet be able to combine data from both.
EDIT in reponse to discussion with @Matt and @batesiiic:
So, picking up on @batesiiic's suggested rewrite of getModyulesDetails to return a Subject, the problem I can't get my head around is how to populate the Modyule.id in the first call and then the Modyule.name in the second call (which doesn't return any reference to the Modyule.id) ie:
private getModyulesDetails = (res: Response) => { // instance method for defining function so that the this.http below refers to the class.
let listOfModyules = res.json();
let modyulesToReturn = [];
let calls = [];
for (let individualModyule of listOfModyules){
/* I REALLY NEED TO POPULATE Modyule.id HERE */
calls.push(
this.http.get(individualModyuleUrl + individualModyule.id + '.json')
.map((res: Response) => res.json()))
);
}
var subject = new Subject<Modyules[]>();
Observable.zip.apply(null, calls).subscribe((modyules: Modyules[]) => {
var modyulesToReturn = [];
modyules.forEach(modyule => {
let tempModyule = new Modyule;
/*I COULD POPULATE Modyle.name HERE BUT IT WON'T MATCH THE Modyule.id SET ABOVE - EXCEPT BY LUCK*/
modyulesToReturn.push(tempModyule);
}
subject.next(modyulesToReturn);
});
return subject;
}
I think I need to make the calls one by one in the for loop but somehow wait until they have all responded before returning the modyulesToReturn?