Tips for using combineLatest when one stream relies on another stream for its behavior?

My Angular resolver is responsible for fetching data from the backend, and I need to make the following calls:

GetProject(projectId): Observable<IProject>
GetSites(projectId): Observable<ISites[]>
GetPersons(siteId): Observable<IPerson[]>

I am attempting to utilize combineLatest but I am unsure of how to implement RxJs in my specific scenario. My goal is to ensure all requests are completed before resolving, with GetPersons() requiring the id of the first item in the result of GetSites(). How can this be accomplished?

Answer №1

To achieve the desired outcome, you may want to combine multiple function calls using concat in this way:

forkJoin([fetchProject(projectId), fetchSites(projectId)]).pipe(
  concatMap(([project, sites]) => {
    const siteId = /* specify here */;
    return fetchPersons(siteId);
  }),
).subscribe(...);

Your approach also depends on whether you require all responses or just the final one in the observer. If you need all responses, then you should connect fetchPersons with map and add the first two responses:

fetchPersons(siteId).pipe(
  map(persons => [project, sites, persons]),
)

Answer №2

Set up a replay subject like this:

const sub = new ReplaySubject(3);

Now, proceed with your calls:

this.getProject(1).pipe(
  tap(project => sub.next(project)),
  switchMap(project => this.getSites(1)),
  tap(sites => sub.next(sites)),
  switchMap(sites => this.getPersons(sites[0].id)),
  tap(person => sub.next(person))
);

Your replay subject will store the project as the first value, sites as the second value, and person as the third value.

If you prefer using the combineLatest approach with a BehaviorSubject:

const obs = new BehaviorSubject([]);
const add = val => obs.pipe(
  take(1),
  map(v => ([...v, val]))
).subscribe(v => obs.next(v));

this.getProject(1).pipe(
  tap(project => add(project)),
  switchMap(project => this.getSites(1)),
  tap(sites => add(sites)),
  switchMap(sites => this.getPersons(sites[0].id)),
  tap(person => add(person))
);

This time, the returned value will be an array containing all values together.

Lastly, here is a way to concatenate them without using a subject:

this.getProject(1).pipe(
  switchMap(project => this.getSites(1).pipe(map(sites => ([project, sites])))),
  switchMap(([project, sites]) => this.getPersons(sites[0].id).pipe(map(person => ([project, sites, person])))),
);

Answer №3

Assigning the project to this.project$ by calling myService.getProject(projectId),
retrieving the sites by calling myService.getSites(projectId),
and fetching persons based on the sites using switchMap and merge functions.
The end result should be an Observable of IPerson[][] which may need to be flattened.

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

Using Angular 2 to bind values to a form select option

I am attempting to dynamically change the color of an element based on the user's selection from a form select dropdown. Currently, I can only achieve this functionality statically. selectedEventGroup: string[]; //this variable stores the user's ...

The parameter cannot be assigned to type 'HTMLCanvasElement | null' due to conflicting arguments

I am encountering an issue with the following code, as it fails to compile: import React, {useEffect} from 'react' import {Card, Image} from 'semantic-ui-react' import * as chart from 'chart.js' export const PieChartCard = ...

Unlock the ability to view the specific child route with the identifier :id

In my application, I have a child component and its parent component. The child component uses the following pipe to subscribe to the activated route: this.route.paramMap.pipe( map(paramMap => +paramMap.get('id')), switchMap((id: number) ...

Updating a property in React by fetching data from API and storing it in the cache

Recently, I implemented nanoid to generate unique IDs for my NBA team stat tracker app. However, upon browser refresh, the fetch function generates new IDs for each team stored in the favorites list. This causes the app to fetch data again and assign a new ...

Filter array of objects by optional properties using TypeGuards

In my TypeScript code, I have defined the following interfaces: interface ComplexRating { ratingAttribute1?: number; ratingAttribute2?: number; ratingAttribute3?: number; ratingAttribute4?: number; } export interface Review { rating: ComplexRati ...

Angular deep linking in an Express server is a powerful combination that allows

I'm developing a single page application using Express and Angular. One feature involves sending users an email with a link to reset their password (https://[domain].com/reset-password/[token]). However, when the user clicks on this link, it redirect ...

Angular: Implementing a Dark and Light Mode Toggle with Bootstrap 4

Looking for suggestions on the most effective way to incorporate dark mode and light mode into my bootstrap 4 (scss) angular application. Since the Angular cli compiles scss files, I'm not keen on the traditional method of using separate css files for ...

Exploring the Potential of Angular 4: Strategies for Integrating Admin and Web Sections in a Unified Project

I'm contemplating whether to create separate projects for the Admin and Web sections in Angular, or if it would be feasible to manage both within a single Angular 4 Application. Any advice on how best to proceed? ...

Exploring ways to fetch an HTTP response using a TypeScript POST request

I have been looking at various questions, but unfortunately, none of them have provided the help I need. The typescript method I am currently working with is as follows: transferAmount(transfer: Transfer): Observable<number> { return this.http .po ...

Tips on expanding typings in TypeScript?

In my software library, there exists a map function with the following definitions: function map<T, U>(f: (x: T) => U, a: Array<T>): Array<U> function map<T, U>(f: (x: T) => U, a: Functor<T>): Functor<U> Furtherm ...

Issue encountered while building Angular 4 application for production due to CSS-loader error

Whenever I attempt to build my application using 'ng build', it works fine. However, when I try to run 'ng build --prod --aot=false' to build it for production, I encounter a perplexing error message: devrep@dev-laptop:~/Document ...

Is there a way for me to verify if my JSON field has been defined?

Currently, I am working on parsing JSON data and attempting to access one of its fields, which happens to be an array. const myObj: MyObj = JSON.parse(myJson); console.log(myObj.myArray); //SyntaxError: Unexpected end of JSON input console.log(myObj.myArr ...

Ways to extract a Bearer Token from an Authorization Header using JavaScript (Angular 2/4)

When working with JavaScript, I have successfully implemented a method for authenticating to my server using an http post request. Upon receiving a response from the server, it includes a JWT in an Authorization header like this: Authorization: Bearer my ...

Enhance user experience with Bootstrap by automatically adding a frame around a card upon clicking

Hello everyone! I am a beginner in the Angular/Web Development world and I am currently working on improving my HTML/CSS skills. While using Bootstrap in my Angular project, I ran into a challenge that I couldn't figure out on my own. I have implement ...

Angular: Modify the spelling of a single term across an application to cater to international audiences

I am working on an Angular application that must support both British and American English languages. The language setting is determined by a server at start-up, allowing me to know which language to display. One specific change I need to make throughout ...

Leveraging RXJS for efficient data retrieval in nodejs

When dealing with sending a bulk of data and moving on to the next one upon completion, it can be quite challenging. Take for instance this function: async function test() { await sample.sampleStructure() await sample.sampleDataAdd() await sample.sa ...

The asynchronous sorting feature in Mat Table, combined with MatPaginator, is currently experiencing issues. The datasource is being assigned asynchronously in

I have been attempting to incorporate matSort functionality into an existing MatTable, however, I am facing difficulties despite following the instructions from a related thread on mat-sort not working on mat-table. It seems like my issue might be due to t ...

The AngularFireAuth.user observable does not trigger when combined with the withLatestFrom RxJS operator

When using the AngularFireAuth.user observable as the source observable, like in the example below: this.AngularFireAuth.user.subscribe((u) => console.log(u)) everything works fine. However, when I try to include it in the withLatestFrom operator, as s ...

Guide on adding a JavaScript array to another array in Angular

In my Angular component, I encountered an issue with a variable called jsonArray:any not being recognized in the template. The error message indicated that it was undefined. import {Component, NgModule} from '@angular/core' import {BrowserModule ...

Is transferring an updated Angular application as straightforward as duplicating a file?

After successfully upgrading my Angular app from version 16 to 18, I have tested it on my local development environment and everything seems to be working smoothly. Now I am wondering about the process of deploying it to my production environment. Is it j ...