Angular2: Dynamic Synchronous Http Requests
Solution 1:
You need to leverage the flatMap
operator to execute your requests in series (one after one). For this, you need to build your data processing chain recursively. The point here is to call the operator on the previous observable (the one returned by the previous request).
This way the request will wait for the previous one to be complete before executed itself. The callback provided when subscribing will be called when all requests were executed.
Here is a sample implementation of this approach:
makeRequest(queryArr, previousObservable){
if (queryArr.length) {
let payload = JSON.stringify(queryArr[0]);
let headers = newHeaders();
(...)
queryArr.splice(0,1);
var observable = null;
if (previousObservable) {
observable = previousObservable.flatMap(() => {
returnthis.http.post('https://testsoapi.apispark.net/v1/entities', payload,{
headers:headers
})
.map((res:Response) => res.json())
.do(() => {
console.log('request finished');
});
});
} else {
observable = this.http.post('https://testsoapi.apispark.net/v1/entities', payload, {
headers:headers
})
.map((res:Response) => res.json())
.do(() => {
console.log('request finished');
});
}
returnthis.makeRequest(queryArr, observable);
} else {
return previousObservable;
}
}
This method can be called initially like this:
test() {
let queryArr = [
{ val: 'test1' },
{ val: 'test2' },
{ val: 'test3' }
];
this.makeRequest(queryArr).subscribe(
() => {
console.log('all requests finished');
});
}
See this plunkr: https://plnkr.co/edit/adtWwckvhwXJgPDgCurQ?p=preview.
Solution 2:
There were a couple syntactical errors in your code as well that would need to be addressed. But those aside you can simplify greatly by using concatMap
+ defer
instead.
let query_arr = ['test1','test2','test3'];
let self = this;
Rx.Observable.from(query_arr).map(JSON.stringify)
.concatMap(payload => {
let headers = newHeaders();
returnRx.Observable.defer(() => {
self.http.post('https://endpoint/post',payload,{headers:headers});
});
}, resp => resp.json())
.subscribe(
data =>console.log('finished http request, moving on to next http request'),
err =>console.error(err),
() =>console.log('all http requests have been finished')
);
The basic idea of this is that it will convert the query array into an Observable then it will eagerly create a series of lazy requests that will only be executed when they are subscribed to. However, by wrapping the post in a defer
each request will only get dispatched when the previous one completes.
Solution 3:
Or a non recursive version in typescript where you give an array to forkjoin
in the return observableObj(res.json()) you know each response when it returns from the httpcall
in the subscribe you know when all responses returned and an array of values
constobservableObj = (obj) => Observable.of(obj)
classRequests {
private query_arr = ['test1','test2','test3']
private url = 'https://testsoapi.apispark.net/v1/entities'publicmake() {
this.processHttp().subscribe(
(d) => {
console.log(d)
},
(e) => {
console.log(e)
},
() => {
console.log("http calls are done")
})
}
privatehttpCall(options : RequestOptions) : Observable<Response> {
let username : string = 'xxx'let password : string = 'yyy'let headers = newHeaders()
headers.append("Authorization", "Basic " + btoa(username + ":" + password))
headers.append("Content-Type", "application/x-www-form-urlencoded")
options.headers = headers
returnthis.http.get(this.url,options)
}
privatecreateRequestOptions(option1 : string) {
let data = {'option1':option1}
let params = newURLSearchParams()
for(var key in data) {
params.set(key, data[key])
}
let options = newRequestOptions({
search: params
})
return options
}
privateprocessHttp() {
returnObservable.forkJoin(
this.query_arr.map(option => {
returnthis.httpCall(createRequestOption(option)).flatMap((res: Response) => {
returnobservableObj(res.json())
})
}))
}
}
Post a Comment for "Angular2: Dynamic Synchronous Http Requests"