Issue
I have some AngularJS(pre 1.5) services using nested calls in a project that we are rebuilding in Angular(11).
The services use nested calls but I have no idea how to rebuild them using RXJS.
Any help, or detailed links to understand how I can get the result I need would be great.
I have not been able to find anything sofar that helps me understand how to resolve this.
This is the original service:
function getBalanceGroups() {
return $http.get(url.format("/accounts/{{accountId}}/balance-groups", $stateParams))
.then(function (response) {
_.each(response.data, function (item) {
getBalanceViews(item.accountBalanceGroupId)
.then(function (balanceViewData) {
item.balanceViews = _.sortBy(balanceViewData, function (view) {
return (view.balanceViewId === item.totalIndebtednessViewId) ? 0 : 1;
});
_.each(item.balanceViews, function (view) {
getBalanceSegments(view.accountBalanceViewId)
.then(function (balanceSegmentData) {
view.balanceSegments = balanceSegmentData;
view.totalBalance = 0;
view.totalBalance = _.sumBy(view.balanceSegments, "balance");
});
});
});
});
response.data = _.sortBy(response.data, function (item) {
return (item.isActive && item.isPrimary) ? 0 : 1;
});
return new LinkedList(response.data);
}, function (error) {
$log.error('Unable to return balance group for the balanceChiclet');
});
}
This is what I have so far: (not working – it is returning the final api data response, I need to use the data to use the data to modify the previous response and return the modified data. No idea how )
getBalanceGroups(accountId: number | string): Observable<any> {
let balGroupsUrl = `/accounts/${accountId}/balance-groups`;
return this.http.get(`${this.baseUrl}${balGroupsUrl}`).pipe(
mergeMap( (groups: any) => groups),
flatMap((group:any) => {
group.balanceViews = [];
return this.getBalanceViews( group.accountBalanceGroupId, group )
}),
mergeMap( (views: any) => views),
flatMap((views: any) => {
return this.getBalanceSegments( views.accountBalanceViewId )
}),
catchError((err) => of(err) ),
tap( groups => console.log('groups: 3:', groups) ),
)
}
private getBalanceViews(accountBalanceGroupId: number | string, group): Observable<any> {
let balViewsUrl = `/balance-groups/${accountBalanceGroupId}/balance-views`;
return this.http.get(`${this.baseUrl}${balViewsUrl}`);
}
private getBalanceSegments(accountBalanceViewId: number | string): Observable<any> {
let balSegUrl = `/balance-views/${accountBalanceViewId}/balance-segments`;
return this.http.get(`${this.baseUrl}${balSegUrl}`);
}
Solution
- Instead of the
mergeMap
+flatMap
(they are synonymous BTW), you could useforkJoin
to trigger multiple requests in parallel. - You might have to use multiple nested
forkJoin
given the nature of the request. - While I’ve converted the loadash
sumBy
usingArray#reduce
, I’ve left thesort
incomplete for you to do it.
Try the following
getBalanceGroups(): Observable<any> {
return this.http.get(`/accounts/${accountId}/balance-groups`, { params: stateParams }).pipe(
switchMap((response: any) =>
forkJoin(
response.data.map((item: any) =>
getBalanceViews(item.accountBalanceGroupId, item).pipe(
map((balanceViewData: any) => ({
...item,
balanceViews: balanceViewData.sort() // <-- incomplete
})),
switchMap((item: any) =>
forkJoin(
item.balanceViews.map((view: any) =>
getBalanceSegments(view.accountBalanceGroupId).pipe(
map((balanceSegmentData: any) => ({
...item,
balanceSegments: balanceSegmentData,
totalBalance: view.balanceSegments.reduce((acc, curr) => acc += curr['balance'], 0)
}))
)
)
)
)
)
)
)
),
map((response: any) => ({
...response,
response.data: response.data.sort() // <-- incomplete
})),
catchError((error: any) => {
console.error('Unable to return balance group for the balanceChiclet');
return of(error);
})
);
}