Optimal method for consecutively making N number of API calls in Angular 9 in a synchronous manner

Having a service method for API calls structured as follows:

getUsers(id){
  return this.http.get(`${env.apiURL}/id`)
}

Now, the requirement is to call this method for a list of users stored in an array:

userId=[1,2,3,4,5,6,7,8,9]

The goal is to retrieve and print results from all API calls by utilizing fork-join as shown below:

    let user1= this.http.get(baseurl+'users/userId[1]');
    let user2= this.http.get(baseurl+'users/userId[2]');//Similarly, there are 10 values

    forkJoin([user1, user2]).subscribe(results => {
      // results[0] corresponds to user1
      // results[1] corresponds to user2
    });

However, it was noticed that the API calls were executed in parallel rather than sequentially. The ideal scenario requires sequential (synchronous) API calls.

Is there a more efficient way to make these n (variable number of users) API calls sequentially? Note: There's also a need to introduce a delay of 500ms after each API call. Attempts with pipe(throttleTime(500)) following the forkJoin operation resulted in simultaneous execution of all API calls.

Answer №1

There are numerous approaches to completing this task. Here are a couple of them:


Method 1:

  users$ = from(this.userIds).pipe(
    concatMap(id => this.getUser(id)),
    take(this.userIds.length),
    toArray()
  );

Steps:

  • from - generates an observable that emits each array element separately
  • concatMap - maps the ID to an observable, subscribes to it, and emits the results. Only permits one subscription to getUser(id) at a time (synchronously)
  • take - indicates how many values our stream should take before completion
  • toArray - gathers emissions and emits them as an array upon completion

Method 2:

  users$ = from(this.userIds).pipe(
    concatMap(id => this.getUser(id)),
    scan((all: User[], user) => ([...all, user]), []),
  );

Steps:

  • from
  • concatMap
  • scan - aggregates emissions into a single array. Emits every time a new value is received.

Both methods should work effectively, but there is a distinction in behavior. Method #1 will emit only once, after all individual calls have finished. Method #2 will emit each time a new value is emitted. (If only one emission is desired, consider using reduce)

Take a look at this StackBlitz to observe the variations in output between the two methods.

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

Encountered Angular error: Maximum call stack size exceeded. Command execution ended with exit code 1

What is the cause of this error? I am executing $ nx build frontend --configuration=production --skip-nx-cache it is invoked from it > ng run frontend:build:production and the error occurs, what could be causing this issue? ERROR in Maximum call stac ...

The error message "Type 'string' cannot be assigned to type 'Condition<UserObj>' while attempting to create a mongoose query by ID" is indicating a type mismatch issue

One of the API routes in Next has been causing some issues. Here is the code: import {NextApiRequest, NextApiResponse} from "next"; import dbConnect from "../../utils/dbConnect"; import {UserModel} from "../../models/user"; e ...

Creating a nested JSON file dynamically in Angular: A step-by-step guide

I am looking to dynamically generate a nested JSON file within an Angular project. The data will be extracted from another JSON file, with two nested loops used to read the information. Below is an example of the initial JSON file structure: { "data": [ ...

Error: Axios header not refreshing automatically in React. User must manually refresh the page

After logging in, I want to update the JWT token in the header before redirecting to the home page. Login.tsx ... const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); const data = new FormData(event.curr ...

Python If/else not working according to plan (or I might just be a bit clueless)

Being a novice, I believe the issue lies in something trivial that I overlooked. Essentially, my goal is to identify websites that have either one or both versions of Google Analytics (UA --> Universal analytics, and GA4 --> Google Analytics 4). In ...

Even with the inclusion of headers in the server code, the Cross-Origin Request is still being

I have a basic API set up in Express/Node and a simple Angular application for posting blogs. However, I am encountering an issue when trying to access the /contribute route using the POST method. The error message that I receive on both Chrome and Firefox ...

"Troubleshooting: The Angular Check-All feature is unexpectedly selecting disabled checkboxes within the ngx data

Within ngx-datatable, I have implemented a functionality where some checkboxes are disabled based on certain conditions. However, when I try to select all checkboxes, even the disabled ones get selected. How can this issue be resolved so that disabled chec ...

Typing in a number will always activate the change event

Having trouble with Angular's change event on numeric input? It doesn't always trigger when clicking the increment or decrement buttons - it only triggers once and then requires the input to lose focus before triggering again. Is there a way to ...

Choosing a value type within an interface or object declaration

Is it possible to extract a nested type object from an interface or parent type? interface IFake { button: { height: { dense: number; standard: number; }; }; otherStuff: string; } type Button = Pick<IFake, 'button'& ...

Tips for setting up ngnix as a proxy server for Angular and NodeJS applications

Currently, I am working on configuring ngnix to run alongside both NodeJS and Angular. As of now, I can successfully access (Server API) and (Angular). However, when attempting to log in with socket.io, I consistently encounter a 'Socket connection ...

Unlocking the Power of Passing Props to {children} in React Components

Looking to create a reusable input element in React. React version: "react": "17.0.2" Need to pass htmlFor in the label and use it in the children's id property. Attempting to pass props to {children} in react. Previously attempte ...

Angular loses focus on MatTableDataSource after updates

Have you encountered the issue where the focus disappears after updating an input element in one row and clicking on the input in the next row? This happens because the datasource gets updated. I have been trying to find a way to preserve the focus while ...

Unable to modify text color after implementing mat-sort-header in Angular Datatable

My current setup involves using an Angular data table to display data. I recently added the mat-sort-header functionality, which allowed me to change the font color of the header text. Below is a breakdown of my code: <section id="main-content" ...

Exploring the typing for DefaultRootState in React Redux Connect

I'm currently in the process of upgrading to the latest versions of TypeScript, React, and Redux. However, I've encountered a compiler error when using the connect function in React Redux: According to the React Redux documentation, I typed my r ...

How come I'm able to access the form's control within setTimeout but not outside of it?

Having just started working with Angular, I came across a strange issue involving forms and setTimeout. When trying to access the form control of an input element inside setTimeout within the OnInit lifecycle hook, it works fine. However, when attempting t ...

In the Angular Google Maps API, is it possible to update the attributes of <agm-marker> directly within the TypeScript code?

Currently, I am fetching markers from the database and displaying them on a map using Angular Google Maps (AGM) by utilizing the <agm-marker> tag. In my code snippet below, you can see how I fetch and store the markers in an array named markers in t ...

Encountering build errors while utilizing strict mode in tsconfig for Spring-Flo, JointJS, and CodeMirror

While running ng serve with strict mode enabled in the tsconfig.json, Spring-Flow dependencies are causing errors related to code-mirror and Model. Any suggestions on how to resolve this issue? ...

Error: The argument provided is of type 'unknown', which cannot be assigned to a parameter of type 'string'. This issue arose when attempting to utilize JSON.parse in a TypeScript implementation

I'm currently converting this code from Node.js to TypeScript and encountering the following issue const Path:string = "../PathtoJson.json"; export class ClassName { name:string; constructor(name:string) { this.name = name; } ...

Angular - developing a custom web element to enhance the project

Is there a way to convert a single module into a web component and integrate it within the same project? Specifically, I have 3 modules in my project and I am looking to transform only module1 into a web component and incorporate it seamlessly. Thank you! ...

Leverage ansible for collecting and updating information, then send the modified JSON data to an HTTP API

When preparing to update a yum based Linux host using Ansible, my goal is to collect information about the currently installed packages and then send this data to an http API. The initial step involves gathering the needed facts and storing them in a vari ...