Using RxJS to merge various HTTP requests into a unified and flattened observable array

Struggling with combining multiple http get requests simultaneously and returning them as a unified, observable array.

In my current setup, the method returnNewCars() retrieves Observable<ICar[]> by executing a single http get request. However, in the scenario of returnAllCars(), I aim to perform multiple http get requests and still return Observable<ICar[]>.

The output of returnNewCars() looks like this:

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

I hope for returnAllCars() to display a similar structure but with all the 6 items included.

Following the guidance from RxJS documentation on forkJoin, I attempted to incorporate it into my code but am unsure of the next steps.

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;
    }
}

Answer №1

If you want to combine your 3 separate arrays into one, simply use .pipe(map(...)) method.

There is no need to pass an object to forkJoin, just 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])
    );
}

Remember that Observables are lazy, so there's no need to wrap them unnecessarily:

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

You can simplify it like this instead:

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

For the allCars() scenario, you can simply do:

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

Answer №2

I'm not entirely sure why you would want to consolidate all car data into one method, as typically you would make separate api calls for each type of car. However, I have attempted to create a single method that retrieves All car data using forkJoin.

You can see the implementation in this stackblitz link

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error in TypeScript on SendGrid API: Invalid HttpMethod

Here is my code snippet: import sendgridClient from '@sendgrid/client' sendgridClient.setApiKey(process.env.SENDGRID_API_KEY); const sendgridRequest = { method: 'PUT', url: '/v3/marketing/contacts', bo ...

Changing the background color of .pane and .view elements in an Ionic web application using JavaScript

Looking to modify the background-color of two css selectors, .pane and .view, that are located within the ionic.css file. Despite multiple attempts to do so using JavaScript directly in the index.html file, the changes are not reflected. The code snippet ...

encountered an issue while accessing a FastAPI-based API

While developing a login feature in Next.js, I encountered an issue when making a request to an API created in FastAPI to retrieve a cookie. The problem arises during the fetch operation on the frontend specifically when setting credentials to 'includ ...

Having difficulty running lint on Vue 3 TypeScript application, but building process is successful

We are encountering an issue at the moment. We can successfully build our app, but we are facing challenges with linting using the vue tools (vue-cli-service ...). The hot-reloading feature works initially, but upon saving a file, we receive an error mess ...

Encountering TypeScript error TS2339 while mocking a React component with Jest

When attempting to mock a React component using Jest, I encountered an issue where TypeScript was not recognizing the mocked methods and showing a TS2339 error. Below is the test code snippet causing the problem: jest.mock('./features/News/News' ...

What is the best way to merge the results of several runs of an observable function

When working with Firestore, I need to retrieve multiple documents, each with a unique sourceAddressValue. This means for a list of N strings, I may need to fetch N documents. I attempted the following approach: getLocationAddresses(addresses: string[]) { ...

Is it possible to include parameters in an HTML GET request with Electron.Net?

I have successfully implemented a function in an Angular component within an Electron application using HttpClient: var auth = "Bearer" + "abdedede"; let header = new HttpHeaders({ "Content-Type": 'application/json&a ...

Using TypeScript to specify the return type of a non-mutating extension function from an external module

Imagine utilizing an external package named "foo". This package's primary export is an object containing an .extend() method that enables functionality addition by generating a derived object (while leaving the original untouched). The process typical ...

Utilize the authenticated page across various tests in Playwright for efficient testing

Starting out fresh with playwright and node.js frameworks Currently in the process of developing a framework using playwright with typescript. Everything was smooth sailing until I reached the point where I needed to run my tests sequentially on the same ...

Introducing the Angular 2/4 Dashboard Widget Module!

I am currently developing the dashboard for my Angular 2 application and I am in search of an npm package that fits my requirements. I came across a link that provides similar functionalities to what I need, which is . I want to be able to add new w ...

Unlocking the union of elements within a diverse array of objects

I have an array of fields that contain various types of input to be displayed on the user interface. const fields = [ { id: 'textInput_1', fieldType: 'text', }, { id: 'selectInput_1', fieldType: 'sel ...

What is the best way to incorporate zone.js into an Angular 2 application?

I have chosen not to use webpack or browserify in my ASP.NET core & Angular2 application. Instead, I am utilizing systemjs to load modules. I am facing a dilemma regarding how to best handle the loading of zone.js within my app. Here are the different opti ...

During the present module, retrieve the runtime list of all modules that are directly imported (Javascript/Typescript)

Imagine you have a set of modules imported in the current module: import {A1, A2, A3} from "./ModuleA"; import {B1, B2, B3} from "./ModuleB"; import {C1, C2, C3} from "./ModuleC"; function retrieveListOfImportedModules() { // ...

Instructions on how to post an array by its ID when the value changes in the form, correspond with the ID

Whenever I change the value in the radio button within a form popup, I want to trigger this action. Below is the corresponding HTML code: <ng-container cdkColumnDef="injected"> <mat-header-cell *cdkHeaderCellD ...

How can I dynamically replace a specific element inside a .map() function with a custom component when the state updates, without replacing all elements at once?

I'm currently developing a task management application and I need to enhance the user experience by implementing a feature that allows users to update specific tasks. When a user clicks on the update button for a particular task, it should replace tha ...

WebStorm is struggling to interpret the syntax of Angular 2

After setting up a new project in Angular CLI and using WebStorm, I've noticed that the IDE doesn't recognize Angular 2 syntax such as *ngFor and lacks autocomplete features for it. https://i.sstatic.net/wwxXQ.png Seeking assistance on enabling ...

Error in Typescript: Function not being triggered on button click

As someone who is just starting out with typescript, I've been tackling a simple code that should display an alert message in the browser when a button is clicked. I've experimented with the button and input tags, as well as using both onclick ev ...

Activate the button when a checkbox within a looping structure is selected using Angular 5

As a relatively new Angular 5 user, I am working with a button that looks like this: <button *ngIf="type!='invoices' && this.action==='edit'" disabled (click)="genera(fields.termini)" class="ml-16 mat-raised-button mat-accen ...

There seems to be a problem fetching the WordPress menus in TypeScript with React and Next

Recently I've started working on a project using React with TypeScript, but seems like I'm making some mistake. When trying to type the code, I encounter the error message: "TypeError: Cannot read property 'map' of undefined". import Re ...

Encountering an error while running npm install - package.json data parsing failed

Encountering an error during npm install on Windows 10, using node v6.10.3 and npm v3.10.10 Please assist in resolving this issue. Error message: npm ERR! npm v3.10.10 npm ERR! file C:\angular2-helloworld\package.json npm ERR! code EJSONPARSE ...