How can I get both responses from 2 Observables simultaneously?

62 views Asked by At

I have 1 service for getting my companies, an Observable array. From the response of that I'm able to use a prop to then get more details from another service.

This is working, but what I want is all the companies returned from the companies service, and each of the details related to those respective companies returned from the details service.

I've tried a variety of combinations of map, mergeMap, etc., but it's not clicking somewhere.

ngOnInit(): void {
    const allCompanies$ = this.companiesService.getCompanies()
    let details$

    details$ = allCompanies$.pipe(
      mergeMap(companies => {
        return companies
      }),
      mergeMap(company => {
        const details$: Observable<any> = this.stocksService.getTickerDetails(
          company.ticker
        )

        return details$
      })
    )

    details$.subscribe(details => {
      console.log(details)
    })
2

There are 2 answers

1
DeborahK On BEST ANSWER

Or, you can use a forkJoin instead of a zip.

Something like this:

    const allCompanies$ = this.getCompanies();

    const details$ = allCompanies$.pipe(
      mergeMap((companies) => 
        forkJoin(companies.map((company) => this.getTickerDetails(company.ticker).pipe(
          map(detail => ({
            company,
            detail
          } as CompanyWithDetail))
        ))))
    );

    details$.subscribe(details => {
      console.log(details)
    })

Here is first gets all of the companies. Then it maps each company in the returned array and gets its details.

It returns a structure that is an array that contains each company with its associated details. You could change this structure as desired to only return the details or whatever.

I added your code to my working example (that is users, posts, and todos). You can find your code in the constructor() of the user.component.ts file here: https://stackblitz.com/edit/angular-posts-user-todos-forkjoin-deborahk

0
Taras Shevhyk On

Try the operator 'zip' to get array of responses like Promise.all()

 import { mergeMap, of, zip } from "rxjs";

of([{ ticker: 1 }, { ticker: 2 }, { ticker: 3 }, { ticker: 4 }])
  .pipe(
    mergeMap((companies) => {
      const observables = companies.map((company) => of(company.ticker));

      return zip(...observables);
    })
  )
  .subscribe((detailes) => {
    console.log(detailes); // output [1, 2, 3, 4]
  });

Example with your code:

getDetails(): void {
this.companiesService
  .getCompanies()
  .pipe(
    mergeMap((companies) => {
      const observables = companies.map((company) => this.stocksService.getTickerDetails(company.ticker));

      return zip(...observables);
    })
  )
  .subscribe((detailes) => {
    console.log(detailes);
  });
}