Leverage the power of forkJoin in JavaScript by utilizing objects or sourcesObject

I'm currently facing an issue with my code snippet below:

getInformations().subscribe(
    informations => {
        let subs = [];
        for (const information of informations) {
            subs.push(getOtherDetails(information.id));
        }
        forkJoin(subs).subscribe(response => {
           //How can I Associate Information Id With The Response
            howToAssociateIdWithResponse();
     }}
);

Situation - My goal is to link the responses from the second call with the ids from the first call, but I'm encountering difficulties.

Attempted - I attempted the following approach which resulted in an error being thrown:

let subs: {[x:number]: Observable<any>}[] = [];
subs.push({information.id: getOtherDetails(info.id)}) 

However, upon subscription, I received an error message stating

You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.


Update - 1 Following @BizzyBob's suggestion, I made adjustments to the code as shown below. However, I am finding that my other logic executes before the subscription completes its task. Here's what I mean:

async ngOnChanges(){
    await getData(); //How to make sure below method only executes when this is really done.
    await useInformationReceivedFromgetData(); 
}
async getData(){
  getInformations().subscribe(
    informations => {
      let subs = [];
      for (const information of informations) {
         subs.push(getOtherDetails(information.id).pipe(
            map(data => ({ id: information.id, data })) // <---
         ));
      }
      forkJoin(subs).subscribe(objects => {           
         objects.forEach(({id, data}) => { /* saved to an arrray */ });
      });
   }

);
}

Answer №1

You have the option to make each instance of "getOtherDetails observable" produce an object containing the id and response data:

getInformations().subscribe(
   informations => {
      let subs = [];
      for (const information of informations) {
         subs.push(getOtherDetails(information.id).pipe(
            map(data => ({ id: information.id, data })) // <---
         ));
      }
      forkJoin(subs).subscribe(objects => {           
         objects.forEach(({id, data}) => { /* utilize id and data here */ });
      });
   }
);

To simplify your code, you can use .map() instead of creating a subs array and adding elements to it:

getInformations().subscribe(
   informations => {
      const subs = informations.map(
         ({id}) => getOtherDetails(id).pipe(map(data => ({ id, data })))
      );
      forkJoin(subs).subscribe(responses => {           
         responses.forEach(({id, data}) => { /* utilize id and data here */ });
      });
   }
);

Furthermore, nesting subscribes inside of subscribes is not recommended. It would be more advantageous to employ a Higher Order Mapping Operator that deals with an "inner subscription" on your behalf. In this scenario, we can utilize switchMap to manage subscribing / unsubscribing from your forkJoin observable:

getInformations().pipe(
   map(informations => informations.map(
      ({id}) => getOtherDetails(id).pipe(map(response => ({ id, data })))
   ),
   switchMap(requests => forkJoin(requests))
).subscribe(
   responses => responses.forEach(({id, data}) => { ... })
);

Answer №2

If you really want to take full advantage of rxjs and its pipe operators, you can go even harder. Here's a sample code snippet:

const combinedResults = getInformations().pipe(
  mergeMap((informations) => {
    return forkJoin(
      informations.map((information) =>
        getOtherDetails(information.id).pipe(
          map((detail) => ({ detail, id: information.id })),
        ),
      ),
    )
  }),
)

combinedResults.subscribe((combinedDetails) => {
  for (const information of combinedDetails) {
    const { detail, id } = information

    console.log('Now you have access to the detail and the id')
  }
})

At first glance, it may seem a bit overwhelming, but this is the "rxjs way" of achieving what you need.

  1. Retrieve the general "informations"
  2. Utilize mergeMap to manipulate the result and create a new observable
  3. Use Forkjoin to merge the array of detail observables
  4. Associate each detail response with the original response using the map pipe
  5. Subscribe only once to access the combined values

This approach makes it easy to showcase the results in an angular template using the async pipe. If your aim is to display the merged values, you won't need to subscribe in your component logic at all, eliminating concerns about performance or memory leaks. Check out this link for more details

<div *ngFor="let item of (combinedResults | async)">{{item | json}}</div>

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

Retrieve JSON data from Form Submission

While I am not a front end developer, I have been trying my hand at it recently. I hope that the community here can assist me with an issue I am facing. I have a form that is supposed to send files to a server-side API like shown below: <form id="uploa ...

The SonarTsPlugin report is coming back clean with no issues found in the Typescript files

In my current project, I am attempting to analyze an Angular application using SonarQube. This particular project consists of a mix of JavaScript and TypeScript files. During the Sonar analysis process, I have noticed that while issues are being generated ...

Use .empty() method to remove all contents from the tbody element after creating a table

Currently, I am working on a project where I am creating a drop-down list to assist users in selecting media and ink for their printers. The goal is to then generate a table displaying the selected results. While I have managed to successfully generate the ...

Passing parameters from a div to a single page component in Vue.js: A complete guide

There is code that appears on multiple pages: <div id="contact-us" class="section md-padding bg-grey"> <div id="contact"></div> <script src="/dist/build.js"></script> </div> Included in main.js is: im ...

I'm looking to leverage axios and useState-useEffect to collect data from numerous web pages. Any suggestions on how to do this efficiently

I stumbled upon a URL that leads to an API with a total of 42 pages and 826 data entries. The URL is . My goal is to store all the data in one variable for future filtering purposes, especially when implementing a "show more" button feature. Initially, on ...

Having difficulty utilizing the $.each() function to assign properties to an object

I have an object called habits that contains some values. var habits={ "Drinking":"No", "Smoking":"No" } I want to add the values from this variable into another variable in the following format: var NewHabits = new Object(); Ne ...

executing a series of jQuery ajax calls iteratively

In my Web Application, I have implemented "Spatial Selection" on a map that allows users to select multiple streets. Once selected, each street is assigned a unique Street Id through the use of a "Selection Handler". The next step in the process involves ...

Unable to expand Bootstrap navbar due to collapsing issue

I recently implemented a collapsed navbar on my website using bootstrap. However, I'm facing an issue where it does not open when clicking on the hamburger menu. After researching various solutions for this problem and trying them out, none of them s ...

What is the best way to eliminate additional values depending on the one I have chosen?

When utilizing the Vuetify v-autocomplete component with the multiple prop, we are able to select multiple values. How can I deselect other values based on the value I have selected? For instance: If I choose the main value, all others will be deselecte ...

After upgrading, my npm is completely dysfunctional – it keeps showing the error "Cannot read property 'get' of undefined."

Recently, I updated Node.js to the latest version on my computer. Prior to the update, the 'npm' command functioned flawlessly in the command prompt. However, after installing the new version of Node.js, it stopped working completely. All comma ...

Leveraging Java and TypeScript code for specific functionalities within an Ionic 2 Android application

When it comes to creating hybrid apps that support Windows, iOS, and Android simultaneously using web technologies such as Html, CSS, and Js, Ionic is the go-to choice. However, there may be certain features not supported by the Ionic 2 framework. Is it ...

Achieving vertical center alignment in React Native: Tips and techniques

Just a quick heads-up: This question pertains to a school project. I'm currently knee-deep in a full-stack project that utilizes React Native for the front-end. I've hit a bit of a snag when it comes to page layout. Here's the snippet of my ...

"A collection of elements in Typescript that is uniform in type, denoted by

Is it possible to declare an array of type any[] where all elements are of the same type? For example: // Allowed const array1: any[] = [1, 2, 3]; const array2: any[] = ['a', 'b', 'c']; // Not allowed because it contains bot ...

What is the procedure for obtaining the corner coordinates of a boundary box in Cesium, expressed in CRS

I am currently developing a project where I am utilizing Cesium to display WMS layers on a map in 2D. To enhance performance, I have opted to use the SingleTileImageryProvider to request only one tile at a time. However, I've encountered an issue whe ...

Understanding the Event Context of Elements using Browser Development Tools

I'm currently investigating the functionality of the search feature on the React Documentation page: https://reactjs.org/ . It's known that they utilize DocSearch, but I'm interested in understanding the inner workings. At the moment, I&ap ...

Utilizing external JSON data in JavaScript for retrieval

Is there a way to retrieve the value of categories.name_category in JavaScript? The AJAX call to the REST API is functioning correctly: https://i.sstatic.net/WJzoL.png I attempted to access it like this, but unfortunately it did not work as expected: ht ...

What is the best way to correlate two arrays of strings with one another?

I am working with two sets of data: First Set: let training = [ "Z1,1545 John Doe,P1", "Z2,2415 Shane Yu,P2" ]; Second Set: let skill = [ "P1, Shooting", "P2, Passing", ]; I need to combine both arrays bas ...

Issue with resolving symbol JSON in Angular 7 when using JSON.stringify

Let me start off by saying that I am new to Angular 7. Currently, I am in the process of developing an application using Angular 7 with a C# backend. The specific challenge I am facing is the need to serialize an object in my component/service before sendi ...

Converting an array of objects to an array based on an interface

I'm currently facing an issue with assigning an array of objects to an interface-based array. Here is the current implementation in my item.ts interface: export interface IItem { id: number, text: string, members: any } In the item.component.ts ...

Executing functions in a pre-defined order with AngularJS: A step-by-step guide

In my AngularJS Controller, I have a receiver set up like this: // Broadcast Receiver $rootScope.$on('setPlayListEvent', function(event, playListData) { if($scope.someSoundsArePlaying === true) { $scope.stopAllS ...