2

I am having a problem on how to approach combining multiple http get requests in parallel and returning it as a flat, observable array.

Currently, I have a method, returnNewCars(), that returns Observable<ICar[]> after making one http get request -- in the method returnAllCars(), I would like to make multiple http get requests and still return Observable<ICar[]>.

Right now, returnNewCars() prints:

(2) [{…}, {…}]
0: {Make: "Honda", Model: "CRV", Year: "2021", Specifications: Array(5)}
1: {Make: "Toyota", Model: "Camry", Year: "2021", Specifications: Array(5)}
length: 2

I would like returnAllCars() to print in the same format, but instead, with all 6 items.

I followed the RxJS doc regarding forkJoin and tried reflect it in my code, however, I don't know where to proceed from there.

app.component.ts

import { Component, OnInit } from '@angular/core';
import { CarsService } from './services/cars.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{

  title = 'AutoZone';

  constructor(private carsService: CarsService){
  }

  ngOnInit(): void {
  }
  
  testConsole(){
    this.carsService.returnNewCars().subscribe(newCars => console.log(newCars));
  }

}

cars.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from "@angular/core";
import { forkJoin, Observable } from 'rxjs';
import { concatMap, map, tap } from 'rxjs/operators';
import { ICar } from '../models/cars.model';

@Injectable({
    providedIn: 'root'
})

export class CarsService{
    carsURL = '/assets/cars.mock.json';
    newCarsURL = '/assets/cars.new.mock.json';
    preownedCarsURL = '/assets/cars.preowned.mock.json';
    usedCarsURL = '/assets/cars.used.mock.json';

    private newCars$: Observable<ICar[]>;

    //Store all http get request to new, preowned, used
    private allCars$: Observable<ICar[]>;

    constructor(private http : HttpClient){
    }
    
    returnNewCars(): Observable<ICar[]>{
        this.newCars$ = this.http.get<ICar[]>(this.newCarsURL);
        return this.newCars$;
    }

    returnAllCars(): Observable<ICar[]>{

        //How do I flatten to return Observable<ICar[]>?
        forkJoin(
            {
                new: this.http.get<ICar[]>(this.newCarsURL),
                preowned: this.http.get<ICar[]>(this.preownedCarsURL),
                used: this.http.get<ICar[]>(this.usedCarsURL)
            }
        )
        
        return null;
    }
}

2 Answers 2

5

You can simply add a .pipe(map(...)) to transform your 3 separate arrays into a single array.

I don't see any reason you need to pass an object to forkJoin, you can simply pass an array:

returnAllCars(): Observable<ICar[]>{
    return forkJoin([
        this.http.get<ICar[]>(this.newCarsURL),
        this.http.get<ICar[]>(this.preownedCarsURL),
        this.http.get<ICar[]>(this.usedCarsURL)
    ]).pipe(
        map(([new, preowned, used]) => [...new, ...preowned, ...used])
    );
}

Also, Observables are lazy, so there's no need to wrap them in a method like this:

    returnNewCars(): Observable<ICar[]>{
        this.newCars$ = this.http.get<ICar[]>(this.newCarsURL);
        return this.newCars$;
    }

You can simply define it like this:

private newCars$ = this.http.get<ICar[]>(this.newCarsURL);

So, in the case for allCars(), you could simply do:

private allCars$ = forkJoin([this.newCars$, this.preOwnedCars$, this.usedCars$])
    .pipe(
        map(([new, preowned, used]) => [...new, ...preowned, ...used])
    );

Sign up to request clarification or add additional context in comments.

Comments

1

I'm not sure why do you need this logic to get all cars with one method since you should make a api call to get 3 kinds cars list separately. Anyway, I tried to make one method to get All as you expected and used forkJoin.

Here is the stackblitz link

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.