In my ngOnInit, I would like to wait for all requests of fetchLists to finish before proceeding:
ngOnInit(): void {
this.fetchLists();
this.route.params.subscribe(params => {
this.doSomethingWithFetchedLists();
}
});
}
fetchLists(): void {
this.httpHandlerCached.getListsA()
.subscribe(listA => this.listA = listA);
this.httpHandlerCached.getListsB()
.subscribe(listB => this.listB = listB);
this.httpHandlerCached.getListsC()
.subscribe(listC => this.listC = listC);
}
Please hear me out, my previous question was closed with a reference to use "forkJoin": Wait for multiple promises to finish
However, with forkjoin I have the exact same issue:
fetchListnames() {
return forkJoin([
this.httpHandlerCached.getListsA(),
this.httpHandlerCached.getListsB(),
this.httpHandlerCached.getListsC(),
]).subscribe(res => {
this.listA = res[0];
this.listB = res[1];
this.listC = res[2];
});
}
So with the proposal to use forkJoin, how can I now wait for the forkjoin to finish before proceeding (meaning before this.doSomethingWithFetchedLists()
is called)?
CodePudding user response:
it's not recommended to put subscriptions inside of subscriptions as suggested by another answer. Instead, one should rely on rxjs pipes and subscribe just once.
In this case, one could think that putting this.route.params
inside the forkJoin
would do the trick, but because this.route.params
will never complete, forkJoin
won't emit (that's how forkJoin
is implemented). To make this.route.params
complete, you can pipe it into take(1)
, resulting in this code:
forkJoin([
this.httpHandlerCached.getListsA(),
this.httpHandlerCached.getListsB(),
this.httpHandlerCached.getListsC(),
this.route.params.pipe(take(1))
]).subscribe(res => {
this.listA = res[0];
this.listB = res[1];
this.listC = res[2];
this.doSomethingWithFetchedLists();
});
You can also use combineLatest
instead of forkJoin
, which instead of waiting for all observables to complete, will emit everytime one of the observables changes (but it will wait for all observables to emit at least one value first).
combineLatest([
this.httpHandlerCached.getListsA(),
this.httpHandlerCached.getListsB(),
this.httpHandlerCached.getListsC(),
this.route.params
]).subscribe(res => {
this.listA = res[0];
this.listB = res[1];
this.listC = res[2];
this.doSomethingWithFetchedLists();
});
If you use the latter approach, you have to unsubscribe manually (or pipe to take(1)
). Otherwise you will have memory leaks.
CodePudding user response:
Adding to Christian's answer, you can use withLatestFrom
to avoid nested subscriptions
fetchListnames() {
return forkJoin([
this.httpHandlerCached.getListsA(),
this.httpHandlerCached.getListsB(),
this.httpHandlerCached.getListsC(),
])
.pipe(
withLatestFrom(this.route.params.pipe(take1)),
map(([res, routeParams]) => {
return { res, routeParams }
})
)
.subscribe(response => {
let res = response.res;
let routeParams = response.routeParams;
this.listA = res[0];
this.listB = res[1];
this.listC = res[2];
this.doSomethingWithFetchedLists();
});
}