Connecting http calls in angular 2 in a for loop
I have some code that looks like
//service.ts
addProduct(productId) {
this.http.post('someUrl', ReqData).map(json).subscribe(doStuff);
}
//component.ts
addAllproducts(productsIds) {
productIds.forEach(productId => service.addProduct(productId);
}
I want you to be able to wait for each call to complete before calling the next productId without using window.setTimeout
..
First, return the observable from your service method:
addProduct(productId) {
return this.http.post('someUrl', ReqData).map(json).subscribe(doStuff);
}
And use a recursive function and call it in the callback subscribe
for each of the elements in your array:
let loop = (id: number) => {
service.addProduct(id)
.subscribe((result) => {
// This logic can be modified to any way you want if you don't want to mutate the `producIds` array
if (productIds.length) {
loop(productIds.shift())
}
})
}
loop(productIds.shift())
How about some recursive calls with . expand () ?
First, create a recursive function and map the data for recursive use:
const recursiveAddProduct = (currentProductId, index, arr)=>{
return service.addProduct(currentProductId)
.map((response)=>{
return {
data:response,
index: index+1,
arr:arr
}
})
};
Now call it recursively into your component:
//productIds is an array of Ids
//start of using the first index of item, where index = 0
let reduced = recursiveAddProduct(productIds[0],0,productIds)
.expand((res)=>{
return res.index>res.arr.length-1 ? Observable.empty(): recursiveAddProduct(productIds[res.index],res.index,productIds)
});
reduced.subscribe(x=>console.log(x));
This is where JSBin works
The advantage of using the operator .expand
:
- You are still using Observables and can chain whatever operators you want.
- You are calling one http after another, which is your requirement.
- You don't need to worry about error handling, they are all tied to the same thread. Just call
.catch
your watchers. - You can do anything according to your recursion method (data manipulation, etc.).
- You can set a condition when the recursion call needs to end.
- One layer code (almost).
Edit
You can use the operator .take()
to terminate your recursion if you don't like the built-in triplet like:
let reduced = recursiveAddProduct(productIds[0],0,productIds)
.expand(res=>recursiveAddProduct(productIds[res.index],res.index,productIds))
.take(productIds.length)
JSBin work
You can use Observable.merge (). Try something like this
addProduct(productId):Observable<Response> {
return this.http.post('someUrl', productId);
}
addAllproducts(productsIds) {
let productedsObservable:Observable<Response>[]=[];
for(let productID in productsIds){
this.productedsObservable.push(this.addProduct(productID));
}
return Observable.merge(productedsObservable)
}
You need to subscribe to the requested function to fulfill the http request. You can read more about combination operators (like merge) here