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

Optimal approach for designing interfaces

I have a situation where I have an object retrieved from the database, which includes assignee and author ID properties that refer to user objects. As I transform a number into a user object, I am unsure about the best practice for defining the type of the ...

Are the missing attributes the type of properties that are absent?

I have a pair of interfaces: meal-component.ts: export interface MealComponent { componentId: string; componentQuantity: number; } meal.ts: import { MealComponent } from 'src/app/interfaces/meal-component'; export interface Meal { ...

Definition file for Typescript Angular 1.5 component

Encountering a problem with typescript and angular 1.5 - when building, an error pops up saying error TS2339: Property 'component' does not exist on type 'IModule'.. Could it be that I overlooked a definition file containing this proper ...

Enhancing Angular2 Routing with Angular4 UrlSerializer for Seamless HATEOAS Link Integration

As a newcomer to Angular4, I am currently exploring how to consume a HATEOAS API. My goal is to either pass an object that contains the self reference or the self reference link itself through the routing mechanism (for example, by clicking on an edit link ...

Multiple Components Sharing the Same ID Attribute in Angular

Recently, I discovered that using the same id attribute for HTML elements in multiple components can lead to repetition of the ID in the DOM when those components are rendered together in the view. Let's consider the following scenario: //hello.comp ...

When Using TypeScript with Serverless, 'this' Becomes Undefined When Private Methods are Called from Public Methods

Currently, I am working on constructing an AWS Serverless function using TypeScript. My focus is on creating an abstract class with a single public method that invokes some private methods. Below is the simplified version of my TypeScript class: export ...

Encountering issues with running npm install on a local Angular project

Whenever I try to execute npm install on my local Angular project, I encounter the following errors: C:\Projects\Angular>npm install npm ERR! code ENOENT npm ERR! syscall spawn git npm ERR! path git npm ERR! errno ENOENT npm ERR! enoent Error ...

Begin a new project with Angular 4 by utilizing the Angular Command Line Interface

Can you guide me on starting a new project with the most recent release of Angular 4 using Angular CLI? The command to initiate this process is as follows: ng new new_project Here are the versions currently installed on my system: - @angular/cli: 1.0 ...

Implementing Formik in React for automatic updates to a Material-UI TextField when blurred

Presently, I am developing a dynamic table where users can simultaneously modify multiple user details in bulk (Refer to the Image). The implementation involves utilizing Material-UI's <TextField/> component along with Formik for managing form s ...

Can someone provide guidance on effectively implementing this JavaScript (TypeScript) Tree Recursion function?

I'm currently grappling with coding a recursive function, specifically one that involves "Tree Recursion". I could really use some guidance to steer me in the right direction. To better explain my dilemma, let's consider a basic example showcasi ...

Angular 4's OrderBy Directive for Sorting Results

I've been working on implementing a sorting pipe based on the code provided in this resource: The issue I'm facing revolves around handling undefined values within my data. The sorting pipe functions correctly when there are no undefined values ...

Error in Typescript: The property 'children' is not included in the type but is necessary in the 'CommonProps' type definition

Encountering this error for the first time, so please bear with me. While working on a project, I opened a file to make a change. However, instead of actually making any changes, I simply formatted the file using Prettier. Immediately after formatting, t ...

Unable to retrieve shared schema from a different schema.graphql file within the context of schema stitching

In my project, I have a user schema defined in a file named userSchema.graphql; id: String! userName: String! email: String! password: String! } In addition to the user schema, I also have separate schema files for login and register functionalit ...

Is it possible to compress an Array comprised of nested Arrays?

I am working on a function that takes in a specific type structure: type Input = [Array<string>, Array<number>, Array<boolean>]; It then transforms and outputs the data in this format: Array<[string, number, boolean]> This essenti ...

The identifier 'name' is not found in the specified data type

How can I resolve the error 'Property 'name' does not exist on type' in TypeScript? Here is the code block : **Environment.prod.ts** export const environment = { production: true, name:"(Production)", apiUrl: 'https://tes ...

In Vue3, when using the `script setup` with the `withDefaults` option for a nested object, its attributes are marked as required. How can this issue

I have defined a props object with certain attributes: interface Props { formList: BaseSearchFormListItemType[], inline?: boolean searchBtn?: { show?: boolean text?: string type?: string size?: string } } const props = withDefaults( ...

What causes the HTML element's X position value to double when its X position is updated after the drag release event in Angular's CDK drag-drop feature?

I am facing a challenge with an HTML element that has dual roles: Automatically moving to the positive x-level whenever an Obsarbalve emits a new value. Moving manually to both positive and negative x-levels by dragging and dropping it. The manual drag a ...

@Viewchild doesn't have access to matSort

In my Angular project, I am having trouble getting my @ViewChild instance to work with MatSort in HTML. component.ts file: import { MatSort } from '@angular/material'; export class MyComponent { @ViewChild(MatSort) sort: MatSort; } ngOn ...

Configuring NextUI with Next.js and TypeScript - CssBaseline component not found in @nextui-org/react package

Struggling to find reliable resources for installing Next.js and NextUI with the latest versions? The most helpful guide I found was this one, but not everything aligns perfectly. The guide instructs me to import CssBaseline like this: import { CssBaselin ...

Having trouble with NPM build getting stuck in Azure DevOps

There seems to be a problem similar to the one discussed in this question: npm run build hangs indefinitely on azure. Our build process has been functioning smoothly for several months. However, we are currently facing an issue where npm build is failing ...