lovis91
lovis91

Reputation: 2171

Angular RxJS map <Observable[]> with api request

In one of my route resolver, I want to get a list of Animals (Animal[]) returned by an API Call. For each animal, I need an extra API call to get the breed name. I tried this :

return this.apiService.get('/api/v1/website/' + environment.web_id + '/useraccount/' + user.id + '/animal').pipe(
  map(animals => animals.map(animalObs => {
    // return animalObs;
    return animalObs.pipe(
      map((animal: Animal) => {
        animal.ani_breed = this.breedService.get(animal.anb_id).pipe(
          map(breed => {
            return breed.anb_name;
          })
        );
        return animal;
      }),
    );
  })),
);

But I get an error when compiling : Type 'Observable' is not assignable to type 'string'. [2322]

I think I am missing something... Please help!

Upvotes: 0

Views: 2386

Answers (2)

ivanavitdev
ivanavitdev

Reputation: 2918

I think what you need is a mergeMap which merge your current request to another request that will request all the returned animals using forkJoin and combine it together.

  getAnimals = () => this.apiService.get('/api/v1/website/' + environment.web_id + '/useraccount/' + user.id + '/animal').pipe(
    mergeMap(animals =>
      Observable.create((observer: Observer<any[]>) => {
        const animals$ = animals.map(
          animal => this.breedService.get(animal.anb_id).pipe(
            map(breed => {
              return {
                ...animal,
                breed_name: breed.anb_name
              }
            })
          )
        );

        forkJoin(animals$).subscribe(result => {
          observer.next(result);
          observer.complete();
        });
      }))
  );

More about forkJoin and mergeMap

https://www.learnrxjs.io/operators/combination/forkjoin.html

https://www.learnrxjs.io/operators/transformation/mergemap.html

EDIT

What you want to do to get the animal and its breed name is return all of the animals property using spread operator and assign the bread name next to it.

        map(breed => {
          return {
            ...animal,
            breed_name: breed.anb_name
          }
        })

FINAL EDIT

Spread operator allows you to enumerate all of the objects property. it has the same output as the code below but in a different procedure.

  map(breed => {
    animal.breed_name = breed.anb_name;
    return animal;
  })

Upvotes: 2

martin
martin

Reputation: 96969

The actual implementation depends on whether you want to run requests in sequence or in parallel but you can do it example like the following:

this.apiService.get('/api/v1/website/' + environment.web_id + '/useraccount/' + user.id + '/animal').pipe(
  mergeMap(animals => {
    const animals$ = animals.map(animal => this.breedService.get(animal.anb_id).pipe(
      map(breed => {
        animal.ani_breed = breed;
        return animal;
      })
    ))

    return forkJoin(...animals$);
  }),
);

Upvotes: 7

Related Questions