Execute multiple observables concurrently, without any delay, for every element within a given list

I've been attempting to utilize mergeMap in order to solve this particular issue, but I'm uncertain if my approach is correct.

Within my code, there exists a method named getNumbers(), which makes an HTTP request and returns a list of numbers (Observable<number[]>).

Additionally, I have a service that includes another method called getData(). This method also makes an HTTP request, but it retrieves data specific to a given number (Observable).

The objective is to execute the first request, and for each number within the result, initiate the second request. All these requests should occur concurrently without waiting for a response. Furthermore, the logic executed after each request is precisely identical.

Presently, I have devised a solution for this scenario, albeit one that does not employ rxjs:

this.getNumbers().subscribe((nums: number[]) => {
    nums.forEach((num: number) => {
        this.myService.getData(num).subscribe((response: Data) => {
            this.rows.push(response);
        })
    })
});

While this implementation produces the desired behavior, it employs nested subscriptions and leaves me unable to determine whether or not the loop has properly concluded. Unfortunately, I require the utilization of rxjs in order to address this issue since I possess a loading spinner that must be set to false once all the calls in the loop are complete.

Hence, how can I restructure this code adequately? Thank you!

Answer №1

You can improve the clarity of your code:

// Avoid using multiple .pipe() calls in succession, it's redundant
this.loadingData$ = this.getNumbers().pipe(
  
  // switchMap automatically transforms an iterable into a stream.
  switchMap(nums => nums),
  // Single-line lambdas don't require braces {} or return statements
  mergeMap(num => this.myService.getData(num))

).subscribe(response => this.rows.push(response));

As an alternative, instead of converting to a stream of numbers, you can convert your array into an array of observables and merge them all.

this.loadingData$ = this.getNumbers().pipe(

  switchMap(nums => merge(...nums.map( 
    this.myService.getData.bind(this.myService)
  )))

).subscribe(this.rows.push.bind(this.rows));

Answer №2

Upon conducting further investigation, I have formulated the following solution:

This.loadingData$ = this.obtainNumbers().pipe(
            switchMap(nums => {
                return of(nums);
            })
      ).pipe(
            mergeMap(num => {
                return this.myService.collectData(num);
            })
        ).subscribe(response => {
            this.addRows(response);
        })

In my template, I can simply verify

if (this.loadingData$.closed)

to indicate whether the spinner should be displayed or hidden

Answer №3

In order to accomplish this, you may utilize the combination of forkJoin and RxJS operators as shown below:

this.fetchNumbers()
  .pipe(
    tap(() => (this.loading = true)),
    switchMap((numbers) =>
      forkJoin(numbers.map((number) => this.myAPI.retrieveData(number)))
    ),
    finalize(() => (this.loading = false))
  )
  .subscribe((dataEntries: Data[]) => {
    this.records.push(dataEntries);
  });

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 the HTTP Post method to retrieve a file object: a step-by-step guide

Is there a way to utilize a http POST request in order to retrieve a file object? Though the uploading of files to the server using the POST request seems successful and flawless, attempting to fetch the file results in an unusual response: console output ...

Is there a way to utilize req.query, req.params, or req.* beyond its original scope without the need to store it in a database?

Looking to streamline my code and apply the DRY pattern, I've been working on creating a helper function for my express http methods. The structure of each method is similar, but the req.params format varies between them. Here's how I attempted t ...

Running the NPM build command results in an error specifically related to an HTML file

I encountered an issue in my AngularJS application when running the command: npm run build -- -prod The error message I received was: ERROR in ng:///home/directoryling/appname-play.component.html (173,41): The left-hand side of an arithmetic operation ...

In TypeScript Next.js 14 APP, object literals are limited to declaring existing properties

I encountered an error in my typescript next.js 14 APP. I need assistance resolving this issue, which states: Object literal may only specify known properties, and 'productPackages' does not exist in type '(Without<ProductCreateInput, Pr ...

Minimize the gap between legend text and icon in Highchart

Is there a way to decrease the space between the number and icon? I am currently working with Angular 8 and Highchart. Below is the configuration of the chart legend. https://i.stack.imgur.com/0dL7y.jpg this.legend = { align: 'center', verti ...

I need to display the Dev Tools on an Electron window that contains multiple BrowserViews. Can anyone advise on how to achieve

My Electron Browserwindow is utilizing multiple BrowserViews to embed web content into the window. These BrowserViews are set based on the tab selected within the window. I can easily open the dev tools for these individual BrowserViews (opening in separ ...

The ActivatedRoute.routeConfig object appears to be empty in an Angular 2 project built with Angular-cli

Two projects I've created using angular-cli are working perfectly fine. However, in one of them, the routeConfig is showing as null and I can't figure out what's causing this issue. Both projects have identical package.json files, so there ...

What is the definition of reusable components within the context of Angular, React, and Vue?

I've been hearing a lot about reusable components. What does this actually mean? For instance, if I want to showcase basic user information like ID, name, age, etc. Does it imply that the component is "plug and play," where you simply write the sele ...

Which types of mouse events are compatible with Angular2?

Exploring mouse events in Angular2 has sparked my curiosity. I have implemented the click event, but now I wonder what other mouse events are available, such as mouseover. Where can I find a comprehensive list of mouse events supported by Angular2? The o ...

Using Jest and TypeScript to mock the return value of react-oidc-context

For our project, we utilize react-oidc-context to handle user authentication using oidc-client-ts under the hood. The useAuth function provided by react-oidc-context gives us access to important information such as isAuthenticated, isLoading, and the auth ...

Sending JSON data from Angular to WCF

Attempting to utilize the post method in Angular to send JSON data to a WCF service. The data is being sent in JSON format from Angular, however, the WCF service is receiving it as a null object. Is it possible to use the get method to send JSON data? Th ...

What is the best way to implement NgClass on a single iteration within NgFor while utilizing parent/child components?

My goal is to toggle the visibility of tiered buttons when a parent button is clicked. I am using ngFor to generate three buttons on tier 1, but I'm struggling to select only the desired tier when clicked instead of affecting all of them. I've m ...

Accessing information necessitates two separate subscriptions

I am posting this inquiry in order to enhance my understanding. Below is an excerpt from my service: export class HomeService { private generalstatistics = new ReplaySubject<object>(); constructor( private http: HttpClient ) { this ...

Issue with ng2-charts not rendering properly on the client side when utilized in Angular version 2.0.0-beta-17

Struggling with using ng2-charts in my Angular 2 app and encountering some challenges. app.ts import {Component} from 'angular2/core'; import {CHART_DIRECTIVES} from 'ng2-charts/ng2-charts'; @Component({ selector: & ...

Exploring the integration of external javascript AMD Modules within Angular2 CLI

During my experience with Angular2 pre-releases, I found myself using systemjs to incorporate external JavaScript libraries like the ESRI ArcGIS JavaScript API, which operates on AMD modules (although typings are available). Now that I am looking to trans ...

Starting object arrays in Angular 6 using ES6

As someone who is just starting out with javascript, I have encountered a challenge with a nested class structure. Specifically, I am looking to initialize an array of EventDate objects and assign it to 'this.dates' within the CustomerEvents cons ...

Instructions on how to implement a readmore button for texts that exceed a specific character length

I am attempting to display a "Read more" button if the length of a comment exceeds 80 characters. This is how I am checking it: <tr repeat.for="m of comments"> <td if.bind="showLess">${m.comment.length < 80 ? m.comment : ...

Creating a Personalized Color Palette Naming System with Material UI in TypeScript

I have been working on incorporating a custom color palette into my material ui theme. Following the guidance provided in the Material UI documentation available here Material UI Docs, I am trying to implement this feature. Here is an excerpt from my cod ...

"Exploring the dynamic duo: Algolia integration with Angular

I've been following a tutorial on implementing instantsearchjs in my website, which can be found here. Everything is set up correctly and I can query for results in .JSON format from my website. However, I'm having trouble figuring out how to r ...

Using Angular 2 to select with default value from a separate model

Is there a way to set the default value or link to another model while utilizing NgFor on a different model? The model intended for binding is as follows: "Bookings": {"dates": [{"date":"3-10-2016","slot":"Full"}, {"date":"4-10-2016","slot":"Full"}, {"da ...