Angular 2 wait until all http.put from end of loop
I have a question. In my program, I need to update several records on the server, so I need to do this through a loop. But I need to get new information from the server. The problem is, how can I wait for a response on all http.put from 201?
Now some code: I have an update function inside a service:
public updateDataonServer(rodz: string, id: number, bodyContent: any) {
let body = JSON.stringify(bodyContent);
let headers = new Headers({ 'Content-Type': 'application/json' });
this.currentUser.setHttpHeader(headers);
let options = new RequestOptions({ headers: headers });
return this._http.put(serverAdress + '/rin/' + rodz + '/' + id,
body,
options).map(res => res.status).catch(this.handleError);
}
and i use it in this function:
changeShow(showId: number, oldShow: MpGruppedGroup[]) {
for (var show of oldShow) {
var paramsDict = {
'DAILY_PLAN_GROUP_ID': show.dailyPlanGroupId,
'DAILY_AIRINGS': show.dailyAirings,
'SHOW_ID': showId
};
this.manager.updateDataonServer('MP_GROUPED', show.dailyPlanGroupId, paramsDict).subscribe((data: any) => {
console.log('status ', data);
});
}
// that should be done after all updates return 201 status
this.getShowDayGroups(showId);
}
source to share
You can use async/await
. First mark updateDataonServer
as asynchronous and change the way http is called like this:
public async updateDataonServer(rodz: string, id: number, bodyContent: any) : Promise<any> {
let body = JSON.stringify(bodyContent);
let headers = new Headers({ 'Content-Type': 'application/json' });
this.currentUser.setHttpHeader(headers);
let options = new RequestOptions({ headers: headers });
const res = await this._http.put(serverAdress + '/rin/' + rodz + '/' + id,
body,
options).toPromise();
return res.status;
}
Then we return the value then()
changeShow(showId: number, oldShow: MpGruppedGroup[]) {
for (var show of oldShow) {
var paramsDict = {
'DAILY_PLAN_GROUP_ID': show.dailyPlanGroupId,
'DAILY_AIRINGS': show.dailyAirings,
'SHOW_ID': showId
};
this.manager.updateDataonServer('MP_GROUPED', show.dailyPlanGroupId,
paramsDict).then(data=> console.log('status ', data));
}
// that should be done after all updates return 201 status
this.getShowDayGroups(showId);
}
Please see this and in case you have any problem converting observable HTTP to Promise take a look at this answer
source to share
You can use RxJS to achieve your desired result:
//extracts the params needed for the put request,
// and returns the result of http.put
// it DOES NOT subscribe to the http.put
updateSingleShowOnServer(show) {
....
// use this function to encapsulate extracting the values from
// your 'show' object and constructing your http.put request
}
// accepts an array of 'shows' and
// returns an observable that emits after every single put request
// has returned a value
updateMultipleShowsOnServer(shows) {
// convert your array of shows into an array of put requests to update shows
let requests$ = shows.map( show => this.updateSingleShowOnServer(show) );
// return an Observable that waits until each request in the requests array
// outputs a value before emitting a value.
// you are going to subscribe to the observable output from this method
return Observable.combineLatest(requests$);
}
My apologies for killing the method names a bit, but I did this to better explain to you what the methods do. Feel free to use your own names in your code.
But using these methods yours changeShow
will become:
changeShow(showId: number, oldShow: MpGruppedGroup[]) {
// IMPORTANT - if any put request fails, this combined request will also fail,
// so you might want an error handler on your subscribe
updateMultipleShowsOnServer(oldShow).subscribe(results => {
// result is an array of the results of all put requests.
this.getShowDayGroups(showId);
}, errors => {
// Optional - do something if you got an error in one of the requests
})
}
Additional note
-
remember to import Observable.combineLatest using `import 'rxjs / add / observable / combinationLatest'
-
combineLatest
will work here because each HTTP request observable emits only once. if, however, you have multiple outliers per observable, therezip
might be a better operator. I prefercombineLatest
it because it tends to be more useful. You must read both statements to understand the differences. -
if that second point doesn't make sense, read a little more on RxJS in general - it's a powerful tool for your toolbox
source to share