Hello I have an API call getItems()
that return data like this :
[
{
name: 'item1',
materials: [
1,
2,
3,
],
},
{
name: 'item2',
materials: [
2,
3,
6,
],
}
...
]
And another API call getMaterial(id)
that return the data of a material like this :
{
name: 'mat1',
img: '/img.jpg'
}
What I'm try to achieve is to get all the items data with the materials data. I manage to have all the observable call for materials but I don't know what to do after.
That's what I've done so far :
public getAllItemsData(): Observable<any> {
return getItems().pipe(
map((list: items[]) => {
return list.map(item => {
const allMat = item.materials.map(m => getMaterial(m))
return forkJoin(allMat).pipe(
map(data => {
return {
...item,
materials: data
}
})
)
})
}),
);
}
But it's not working. Thank for the help.
CodePudding user response:
Try this. Using switchMap, mergeMap, from, forkJoin
getItems()
.pipe(
switchMap((items) =>
// for each items
from(items).pipe(
// merge map to run parallel for each items
mergeMap(({ materials, ...item }) =>
// wait to retrive all materials details of current item at mergeMap
// after completing use map to map item with retrived materials
forkJoin(
materials.map((m) => this.getMaterial(m))
).pipe(map((materialDetails) => ({ ...item, materials: materialDetails })))
)
)
)
)
.subscribe((result) => {
console.log(result);
});
CodePudding user response:
Very similar to the above just with less nested pipes
interface Item {
name: string;
materials: number[];
}
interface MaterialData {
name: string;
img: string;
}
public getAllItemsData() {
return getItems().pipe(
switchMap((items: Item[]) => from(items)), // use 'from' to deal with one Item at a time
mergeMap(({ materials, name }: Item) =>
forkJoin(materials.map((mat) => getMaterial(mat))) // create array of observables using map, and pass into forkJoin
.pipe(
map((materials) => ({ name, materials })), // reconstruct object
),
),
toArray(), // collect all emissions and output as an array
);
};