Issue
I have an Angular application that needs to make multiple calls to a spring boot API. First, a call returns a List of Entry-Objects. Each Entry Object has a property called medIds, which is a List of ids for different Objects of type Medication. Now I need to first make the call to receive the Entry-Objects. Depending on the results of this call, I need to make calls to a different API Endpoint to receive the corresponding Medication objects to the list of medIds. This is what I have come up with so far:
getForUser() {
this.entryService.getForUser().pipe(
switchMap(entries => {
const medicationObservables = entries.map(entry => entry.medIds.map(id => this.medicationService.getById(id)));
return forkJoin(medicationObservables);
})
).subscribe({
next: medications => {
medications.forEach(medicationArray => {
medicationArray.forEach(medication => {
console.log(medication);
});
});
},
error: err => {
console.log(err);
}
});
}
However, this does simply log nothing. Is there something wrong with my understanding of how RxJS handles multiple dependent API calls? I am a bit confused regarding switchMap
and forkJoin
.
Solution
Once we get the entries, we loop through the entries and get the medIds
After that we need to loop through the medIds
of each entry and set them each to an API observable, that will return the output of observalbes.
Using this returned array of observables (containing the API for each of the medIds), we set this array to a forkJoin which will get the Ids as a group.
Then the outer map will be again assigned to a forkJoin.
The output can be accessed with a map
, using this map, we loop through each of the entries, since the medIds are grouped by forkJoin, we will get the array of medIds for an entry on the same index as the entry. Thus we can simply assign the medIds to an inner array of entries called medications
, we can do a null check to ensure an array is always set, finally since the map returns the formatted values, we can simply subscribe to it and access the final result!
main.ts
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { forkJoin } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import 'zone.js';
import { EntryService } from './entry.service';
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>Hello from {{ name }}!</h1>
<a target="_blank" href="https://angular.dev/overview">
Learn more about Angular
</a>
`,
})
export class App {
name = 'Angular';
constructor(private entryService: EntryService) {}
ngOnInit() {
this.getForUser();
}
getForUser() {
this.entryService
.getForUser()
.pipe(
switchMap((entries: any) => {
const medicationObservables$: any = entries.map((entry: any) =>
forkJoin(
entry.medIds.map((id: any) => this.entryService.getById(id))
)
);
return forkJoin(medicationObservables$).pipe(
map((medicationArray: any) => {
entries.forEach((entry: any, index: number) => {
entry.medications = medicationArray?.[index]?.length
? medicationArray[index]
: [];
});
return entries;
})
);
})
)
.subscribe({
next: (entries) => {
console.log(entries);
},
error: (err) => {
console.log(err);
},
});
}
}
bootstrapApplication(App);
service.ts
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class EntryService {
constructor() {}
getForUser() {
return of([
{ id: 1, medIds: [1, 2, 3] },
{ id: 2, medIds: [1, 2, 3] },
{ id: 3, medIds: [1, 2, 3] },
{ id: 4, medIds: [1, 2, 3] },
]);
}
getById(id: any) {
return of({
test: Math.random(),
});
}
}
Answered By - Naren Murali
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.