Home > database >  Angular Loop on fetched observable array data and fetch another array of data in it
Angular Loop on fetched observable array data and fetch another array of data in it

Time:10-10

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
    );
};
  • Related