Reputation: 730
I am trying to migrate an existing AngularJs code to Angular 5. I currently run a number of API calls in a forEach function. Previously I used to run $q.defer in each for each funtion, and .resolve() in both success or error function call. After that $q.all. Right now I am not sure how to use it with observables.
This is how my component looks.
testArray = [1,2,3,4,5,.6];
resultArray = [];
constructor(private timeoutService: TimeoutService) {
this.testFn();
}
testFn(){
this.testArray.forEach((n) => {
this.timeoutService.getItemsCallback(n, this.successFn.bind(this), this.errorFn.bind(this))
})
}
successFn(r){
this.resultArray.push(r);
console.log(r)
}
errorFn(e){
this.resultArray.push(e);
console.log(e);
}
And this is my service file.
public GetItems(request: any): Observable<any> {
console.log(request)
return this.http.get(`https://jsonplaceholder.typicode.com/posts/${request}`);
}
getItemsCallback(request, successFn, errorFn) {
this.GetItems(request).
subscribe(
response => {
successFn(response);
},
error => {
errorFn();
}
);
}
I want to do something after all the API calls finish. I see there's a function called forkJoin, but I am not sure how to use it. Here's a stackblitz link for this. https://stackblitz.com/edit/angular-suetah?file=src%2Fapp%2Ftimeout.service.ts
Upvotes: 0
Views: 1031
Reputation: 2225
This has multiple solutions using RxJS.
This answer is an addition to Picci's answer.
Picci uses MergeMap. The problem with MergeMap is that the order of responses that you get may sometimes not be the same as the order of requests.
ForkJoin, will preserve the order and will return after all responses have been received.
ConcatMap will preserve the order but will return after completion of each request.
If you are not concerned about the time taken to wait before all requests are complete, I suppose you can use ForkJoin.
It will be something like this:
testArray = [1,2,3,4,5,6];
obsArray = []
this.testArray.forEach((n) => {
this.obsArray.push(this.timeoutService.getItemsCallback(n))
})
forkJoin(this.obsArray).subscribe((res) => {
//Write code for success callback
},
(err) => {
//Write code for error callback
},
() => {
//Write code to do something when all requests are complete
})
However if you want to use mergeMap or concatMap (Read my explanation above and decide), you can do what Picci has done.
Just change mergeMap to concatMap in his code, if you decide to go with concatMap.
Upvotes: 1
Reputation: 17762
If you have several http calls to execute, with parameters stored in an array, and then you have to do something specific when all these calls have returned, you can consider an approach along these lines.
First of all you create an Observable from the array of parameters using the from
function of RxJs 6.x.
Then you use mergeMap
(a.k.a. flatMap
) to transform the array of Parameters in an array of Observables representing the http calls.
Finally you subscribe to activate the Observable chain and execute the calls, specifying the function you want to run when the Observable chain completes, i.e. when all http calls have returned.
The code could look like the following
const testArray = [1,2,3,4,5,6];
from(testArray)
.pipe(
mergeMap(param => this.GetItems(param))
)
.subscribe(
result => {// do something with the result},
error => {// do something if an error occurs},
() => {// this is the function run when all of the httpCalls have returned}
)
Upvotes: 0