I have a subscription inside of a for loop that fetches JSON data as a series of "category data" from an external source, then filters that data based on the users current location. What I need is to wait for all of the subscriptions to complete, and then and only then can my app proceed. Right now, it does not wait for all of the subscriptions to complete, it only completes a few, and then proceeds, while the other subscriptions continue in the background.
I've tried the following "brute force" method, where i know a certain number of categories will be added to the filtered array, and it works, but I don't know how to make it work for any situation.
Here's my code:
getMultipleCategoryData(categoryIds: string[]) {
for (let i = 0; i < this.waypointIds.length; i++) {
//after user selects their categories, its added to waypointNames, and occurences() gets the # of occurences of each waypoint name
let occurences = this.occurences(this.waypointNames[i], this.waypointNames);
this.categoryApi.getCategoryData(this.waypointIds[i]).toPromise().then(data => {
let filteredLocs = data.locations.filter(loc => this.distanceTo(loc, this.hbLoc) < MAX_RADIUS);
let foundLocs = [];
//fill filteredLocs with first n, n = occurences, entries of data
for (let n = 0; n < occurences; n++) {
if (filteredLocs[n] != undefined) {
foundLocs[n] = filteredLocs[n];
}
}
//find locations closest to hbLoc (users current location), and add them to waypoints array
for (let j = 0; j < foundLocs.length; j++) {
for (let k = 0; k < filteredLocs.length; k++) {
if (this.distanceTo(this.hbLoc, filteredLocs[k]) < this.distanceTo(this.hbLoc, foundLocs[j]) && foundLocs.indexOf(filteredLocs[k]) < 0) {
foundLocs[j] = filteredLocs[k];
}
}
}
if (foundLocs.length > 0 && foundLocs.indexOf(undefined) < 0) {
for (let m = 0; m < foundLocs.length; m++) {
this.waypointLocs.push(foundLocs[m]);
}
}
}).then(() => {
//this hardcoded, brute force method works, but i'd need it to be more elegant and dynamic
if (this.waypointLocs.length >= 5) {
let params = { waypointLocs: this.waypointLocs, hbLoc: this.hbLoc };
this.navCtrl.push(MapPage, params);
}
});
}
}
And the categoryApi.getCategoryData method:
getCategoryData(categoryId): Observable<any> {
// don't have data yet
return this.http.get(`${this.baseUrl}/category-data/${categoryId}.json`)
.map(response => {
this.categoryData[categoryId] = response.json();
this.currentCategory = this.categoryData[categoryId];
return this.currentCategory;
});
}
Everything is working fine except waiting for the subscriptions to complete, I'd really like a way to determine when all of the subscriptions have completed. Any help is appreciated!
You can collect all observables in an array and use forkJoin
to wait for all of them to complete:
let observables: Observable[] = [];
for (let i = 0; i < this.waypointIds.length; i++) {
observables.push(this.categoryApi.getCategoryData(this.waypointIds[i]))
}
Observable.forkJoin(observables)
.subscribe(dataArray => {
// All observables in `observables` array have resolved and `dataArray` is an array of result of each observable
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With