Enhancing RxJS arrays of Observables with supplementary data for preservation

Question: Processing Array of Observables with Metadata in Angular

How can I process an array of Observables, such as using forkJoin, while passing additional metadata for each Observable to be used in the pipe and map functions?

const source = {animal: 'cat', fruit: 'apple', color: 'blue'}
const observables = Object.keys(source).map(key => [this.getDataFromApi(source[key]), key])

// Need to resolve only observables[0][0], observables[0][1], observables[0][2] in a special way,
// while preserving observables[1][0], observables[1][1], observables[1][2] for future use in pipe and map
const processedObservable = forkJoin(observables).pipe(
  map(items => items.map(item => 'This is ' + item[0] + '(' + item[1] + ')')),
  map(items => items.join(', '))
)

processedObservable.subscribe(text => console.log(text)) // For testing purposes
// Expected result: This is your cat (animal), This is your apple (fruit), This is your blue (color)

Description

I have a "source" object containing items. I need to make API requests for each item to get an array of Observables. Then, I want to process all the received data by using forkJoin followed by various map functions within the pipe.

Please note that direct processing in subscribe is not possible.

Here is a simple example without metadata:

const source = ['cat', 'apple', 'blue']
const observables = source.map(item => this.getDataFromApi(item))
const processedObservable = forkJoin(observables).pipe(
  map(items => items.map(item => 'This is ' + item)),
  map(items => items.join(', '))
)
processedObservable.subscribe(text => console.log(text)) // Test output
// Result: This is your cat, This is your apple, This is your blue

In addition to the item data for API requests, I also have metadata associated with each item that needs to be utilized during processing in the pipe and map functions.

Though the examples provided show how to ignore metadata or keys, here we focus on incorporating metadata:

const source = {animal: 'cat', fruit: 'apple', color: 'blue'}
const observables = Object.keys(source).map(key => this.getDataFromApi(source[key]))
const processedObservable = forkJoin(observables).pipe(
  map(items => items.map(item => 'This is ' + item)),
  map(items => items.join(', '))
)
processedObservable.subscribe(text => console.log(text)) // Test output
// Result: This is your cat, This is your apple, This is your blue

The following example shows how to include metadata but doesn't perform API calls or utilize keys:

const source = {animal: 'cat', fruit: 'apple', color: 'blue'}
const observables = Object.keys(source).map(key => of(key))
const processedObservable = forkJoin(observables).pipe(
  map(items => items.map(item => '(' + item + ')')),
  map(items => items.join(', '))
)
processedObservable.subscribe(text => console.log(text)) // Test output
// Result: (animal), (fruit), (color)

The desired outcome is:

// Result: This is your cat (animal), This is your apple (fruit), This is your blue (color)

A solution may involve modifying the forkJoin call to include both the array of Observables and the metadata associated with each item:

const observables = Object.keys(source).map(key => [this.getDataFromApi(source[key]), key])

Consider using alternative functions like flatMap or switchMap if necessary.

Additional Information

The method getDataFromApi simulates API calls:

getDataFromApi(item) {
    return of('your ' + item)
}

Answer №1

It is recommended to integrate your initial map directly within the creation of individual observables.

const source = { animal: "cat", fruit: "apple", color: "blue" };

const observables = Object.keys(source).map(key => getFromApi(source[key]).pipe(
  map(item => `this is ${item} (${key})`)
));

const processedObservable = forkJoin(observables).pipe(
  map(items => items.join(', '))
);

processedObservable.subscribe(console.log);

https://stackblitz.com/edit/rxjs-4x7hbv?file=index.ts

Answer №2

Here is a sample illustration of how this implementation could be carried out:

from(Object.entries(data))
 .pipe(
   mergeMap(([key, value]) => fetchData(value).pipe(
     map(item => `Result: ${item} (${key})`), 
   )),
   toArray(),  
   map(item => item.join()), 
 )
 .subscribe(console.log);

Feel free to test the demo below:

const { from, of } = rxjs;
const { map, switchMap, toArray } = rxjs.operators;

function fetchData(item) {
  return of('data ' + item)
}

const data = { person: "John", food: "pizza", place: "beach" };

from(Object.entries(data))
  .pipe(
    mergeMap(([key, value]) => fetchData(value).pipe(
      map(item => `Result: ${item} (${key})`), 
    )),
    toArray(),  
    map(item => item.join()),
  )
  .subscribe(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.6.2/rxjs.umd.min.js"></script>

Answer №3

function fetchInformation(item) {
  return of('your ' + item)
}

const data = { animal: 'cat', fruit: 'apple', color: 'blue' };

from(Object.keys(data)).pipe(
  switchMap(key => forkJoin([fetchInformation(data[key]), of(key)])),
  map(([response, key]) => `this is ${response} (${key})`),
  toArray(),
  map(result => result.join(', ')),
).subscribe(console.log);

Refer to: https://stackblitz.com/edit/rxjs-1t4nlo?file=index.ts

Answer №4

Give this a shot using

import { combineLatest } from 'rxjs'

 combineLatest(['dog', 'banana', 'green'].map(item => this.fetchDataFromServer(item))).pipe(
    map(items => items.map(item => 'this is ' + item)),
    map(items => items.join('; '))
  )
  .subscribe({
    next:(res) => console.log(res)
  })

Check out the demo on stackblitz

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

What is the process for configuring React on one server and springboot on a separate server?

Can you help me with the setup of the following: Web Server : I need to set up a react + typescript application using npm at Backend Server : I also need to configure a Springboot backend server at I am currently using webpack to build the react applica ...

The element is inferred to have an 'any' type due to the inability to use a 'string' type expression to index the 'Palette' type

Encountering an issue: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Palette'. No index signature with a parameter of type 'string' was found on type &ap ...

Creating a dynamic form in Angular based on user input

I am in the process of creating a dynamic web form where the user's input will determine the subsequent form inputs that are generated. For example: <mat-form-field> <mat-select placeholder="Type" [(ngModel)]="row.Type" (change)="Typ ...

The number of keys in the related object must correspond to the length of the array in Advanced Generic Types

Can we achieve type safety across rows and columns by having one object define the structure of another? Starting Point: export interface TableColumn { name: string; type: "string" | "number" | "action"; id: string; } ...

Angular 2 event emitter falling behind schedule

I am currently utilizing Angular 2 beta 6. The custom event I created is not being captured import {Component, OnInit, EventEmitter} from 'angular2/core'; import {NgForm} from 'angular2/common'; import {Output} from "angular2/core" ...

Allow only numerical values through an ion-input in Ionic 4, preventing the input of letters and special characters

I am currently developing an application in Ionic 4 that requires users to enter only integer numbers (0-9). I need to prevent any other characters such as alphabets, dots, or plus signs from being entered. However, the methods I have tried so far have not ...

Button with circular icon in Ionic 4 placed outside of the toolbar or ion-buttons

Is it possible to create a circular, clear icon-only button without using ion-buttons? I am trying to achieve the same style as an icon-only button within ion-buttons (clear and circular). Here is my current code: <ion-button icon-only shape="round" co ...

Setting up Electron with React and TypeScript: A Comprehensive Guide

I've been developing an app using Electron, React (jsx), and Babel. However, I recently made the switch to TypeScript and I'm struggling to get everything functioning properly. The npm packages I've tried only work for either React or TypeSc ...

Troubleshooting the Ng2-Charts Linechart to display all values instead of just the first two

Starting a new Angular application with the Angular-CLI (beta 22.1) has presented an issue when adding test data (5 values) to a chart. The scaling appears incorrect, displaying only the first two values stretched across the entire length of the graph (ref ...

Display sub-objects within Chart.js

I'm currently tackling a project in Ionic 3 where I am utilizing an API that returns a JSON response with nested objects. My goal is to display certain aspects of these objects within a bar graph using chart.js. Unfortunately, I lack experience in ma ...

Unable to locate youtube.ts file in the Angular 2 project for the YoutubeAPI integration

I've been using a youtube.d.ts file from the DefinitelyTyped project. It functions perfectly in my WebStorm while I'm editing, but once I try to run it, I encounter a 404 error stating that typings/youtube.js is not found. This file doesn't ...

Convert JSON data into an array of strings that are related to each other

I'm encountering an issue with converting JSON into a string array I must convert a JSON into a string array to dynamically INSERT it into our database, as I need this to work for any type of JSON without prior knowledge of its structure. Here is th ...

Obtaining Data from an Array with Reactive Forms in Angular 4

Just starting out with Angular 4 and trying to figure out how to populate input fields with information based on the selection made in a dropdown. <select formControlName="selectCar" class="form-field"> <option value="">Choose a car&l ...

Troubleshooting Issue: Ionic 3 and Angular ngForm not transmitting data

Attempting to create a basic crud app with ionic 3, I am encountering an issue where new data cannot be inserted into the database. The problem seems to lie in the PHP server receiving an empty post array. Below is my Ionic/Angular code: Insert.html < ...

The Angular router is directed to an empty URL path instead of the specified URL

I have encountered a strange issue while developing my angular app which involves the router functionality. All routes were working perfectly fine until I discovered that after a successful login, instead of navigating to the '/admin' path as int ...

Dealing with problems related to types in React and TypeScript createContext

Struggling to pass the todos (initial state) and addNewTodo (methods) using React Context hook and typescript. Despite trying multiple solutions, errors persist. Partial generics do not cause issues in the context component, but I encounter the error Cann ...

Programmatically click a button from the library by triggering a click on its outer div using Angular

Currently, I'm just starting out with Angular. I've been using the @abacritt/angularx-social-login package and noticed that the Google button it provides is only an icon. I'd like to customize its appearance by placing the icon inside a div ...

Enable the use of unfamiliar techniques on object

I am facing a challenge with an object that contains multiple method names which are not known at compile time. The signature of these methods always remains the same, but I am unsure about how to handle this scenario. I attempted to utilize an index type ...

Tips for sorting/merging/consolidating data in Angular

Take a look at this code snippet: rowData = [ [ '2019-12-10 08:00:00', '2019-12-10 08:00:00', '2019-12-10 08:00:00', '2019-12-10 08:00:00', '2019-12-10 08:00:00', '2018-12-10 08:00:00' ...

Caution: The `id` property did not match. Server: "fc-dom-171" Client: "fc-dom-2" while utilizing FullCalendar in a Next.js environment

Issue Background In my current project, I am utilizing FullCalendar v5.11.0, NextJS v12.0.7, React v17.0.2, and Typescript v4.3.5. To set up a basic calendar based on the FullCalendar documentation, I created a component called Calendar. Inside this comp ...