Updating the user interface after each observable completes its task within a forkJoin operation in Angular

Recently, I encountered an issue related to making multiple API calls using forkjoin in Angular. One specific code snippet that I used for the API call is as follows:

  postdata1(body: any): Observable<any> {
    // Receive body as a parameter
    // Declare headers here if they were special to this request in a global scope if not
    return this.http.post(this.baseUrl + 'dictionary/getrae', body, {
      headers: headers,
      responseType: 'text',
      withCredentials: true,
    });
  }

As I needed to make approximately 20 such calls, I wanted to create a "status bar" that would display the progress percentage and completion status of each post.

Each call would increment the progress percentage and change a message on the interface. However, due to the service being attached, I faced issues updating the interface immediately after each post instead of waiting for all posts to complete before refreshing the UI.

My main question is:

How can I update the interface from the service simultaneously with the completion of each individual post, rather than waiting for all posts to finish?

Thank you in advance.

UPDATE:

The ultimate goal is to achieve a UI update like the following:
step 1 done
step 5 done
step 2 done
step 3 done
step 6 done
step 4 done
finish!

The order of the steps does not matter, but 'finish!' should be displayed at the end.

Below is the code snippet I utilized for forkjoin:

nuevoenviar() {
    this.palabrabuscada = $("#inputword").val();
    const body = JSON.stringify(this.palabrabuscada);

    let data1$ = this.dataService.get1(body);
    let data2$ = this.dataService.get2(body);
    let data3$ = this.dataService.get3(body);
    let data4$ = this.dataService.get4(body);
    let data5$ = this.dataService.get5(body);
    let data6$ = this.dataService.get6(body);

    return forkJoin([data1$, data2$, data3$, data4$, data5$, data6$]).subscribe((responses) => {

      this.statusfinish = "step 1...";
      this.result1 = responses[0];
      this.porcentaje += this.porcentajeparte;

      this.statusfinish = "step 2...";
      this.result2 = responses[1];
      this.porcentaje += this.porcentajeparte;

      this.statusfinish = "step 3...";
      this.result3 = responses[2];
      this.porcentaje += this.porcentajeparte;

      this.statusfinish = "step 4...";
      this.result4 = responses[3];
      this.porcentaje += this.porcentajeparte;

      this.statusfinish = "step 5...";
      this.result5 = responses[4];
      this.porcentaje += this.porcentajeparte;

      this.statusfinish = "step 5...";
      this.result6 = responses[5];
      this.porcentaje += this.porcentajeparte;

      this.finalizar(); // This is where your method needs to be called
    });
  }

Answer №1

To effectively track progress for each Observable, consider updating it within a tap function.

nuevoenviar() {
    this.palabrabuscada = $("#inputword").val();
    const body = JSON.stringify(this.palabrabuscada);

    let data1$ = this.dataService.get1(body).pipe(tap(r => {
      this.statusfinish = "step 1...";
      this.result1 = r;
      this.porcentaje += this.porcentajeparte;
    }));
    let data2$ = this.dataService.get2(body).pipe(tap(r => {
      this.statusfinish = "step 2...";
      this.result2 = r;
      this.porcentaje += this.porcentajeparte;
    }));
    let data3$ = this.dataService.get3(body).pipe(tap(r => {
      this.statusfinish = "step 3...";
      this.result3 = r;
      this.porcentaje += this.porcentajeparte;
    }));
    let data4$ = this.dataService.get4(body).pipe(tap(r => {
      this.statusfinish = "step 4...";
      this.result4 = r;
      this.porcentaje += this.porcentajeparte;
    }));
    let data5$ = this.dataService.get5(body).pipe(tap(r => {
      this.statusfinish = "step 5...";
      this.result5 = r;
      this.porcentaje += this.porcentajeparte;
    }));
    let data6$ = this.dataService.get6(body).pipe(tap(r => {
      this.statusfinish = "step 6...";
      this.result6 = r;
      this.porcentaje += this.porcentajeparte;
    }));

    return forkJoin([data1$, data2$, data3$, data4$, data5$, data6$]).subscribe((responses) => {
      this.finalizar(); // Call your method here
    });
  }

If maintaining order is crucial, consider using concat instead of forkJoin as it preserves the sequence of Observables. However, note that step completion may not occur in the same order. Be mindful of this when implementing your solution.

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

Is it possible for me to exclude generic parameters when they can be inferred from another source?

Imagine having a scenario like this: type RecordsObject<T, K extends keyof T> = { primaryKey: K; data: Array<T>; } where the type K is always derived from the type T. Oftentimes, when I try to declare something as of type RecordsObject, ...

Tips for effectively documenting interface properties within compodoc for Angular 2

Recently, I started using compodoc to document my app and I am facing some challenges in writing clean code while documenting the openWeather API interface. I attempted to use the conventional @property JSDoc marker but it does not seem to work well with ...

Issue with Angular: event.key doesn't register as shft+tab when pressing Shift+Tab key

Our website features a dropdown menu that can be opened and closed by clicking, revealing a list of li items. However, we are currently experiencing an issue with keyboard focus navigation. When the Tab key is pressed, the focus properly moves from one li ...

Get Fit with Dynamic Programming

Currently delving into the realm of reactive programming using RxJS, I encountered the following exercise: Initialization of an empty array Upon application launch, a new Date() is added to the array Each mouse click appends a new value to the array alon ...

The evaluation of mongodb-memory-server is experiencing issues with either failing or timing out

While setting up mongodb-memory-server in my backend for testing purposes, I encountered some issues during test execution that require debugging. The problem arises when running a test that creates a MongoDB document within the service being tested, leadi ...

How do I transfer a PDF received from a third-party to my client using a REST API on the backend?

After receiving a PDF from a third party, I stored the file on S3. Upon checking the file on S3, I was able to view the PDF without any issues. However, when sending the PDF to the client and verifying it using Postman, an empty PDF is displayed. Below is ...

Preventing duplicate arrays from being stored in localStorage by validating them

Is there a way to ensure that when the "add to favorites" button is clicked, its data is stored in localStorage only once? If it already exists in localStorage, clicking for a second time should not have any effect except showing an alert message. I would ...

Apply a dynamic function to assign a background color to a specific class

Currently, I have a function called getBackground(items) that returns a background color from a JSON file list. Within my application, there is a component that automatically adds a class name (.item-radio-checked) when a user clicks on an item in the list ...

Errors with optional chaining operator (?.) in node_modules directory when using Node, Typescript, and tslint

My node script works perfectly with node versions up to 17: $ nvm use 17 Now using node v17.9.1 (npm v8.11.0) $ cd src $ npx tsc $ npx node parser.js $ cd .. However, starting from node version 18, it throws an error related to the optional chaining opera ...

Creating an eye-catching animation in Angular 2+ by applying a checkbox check effect to each checkbox dynamically generated within a loop

When I integrated a CSS animation for checkbox "cards" into an Angular project, the transition ceased to function properly. I have limited experience with Angular and am trying to work with existing code. While I managed to get a basic animation working wi ...

Utilizing a responsive design with a bootstrap grid system, featuring expandable columns for

After creating a bootstrap grid page, I am facing an issue with the layout on mobile screens. My problem arises when trying to reorder the cards properly for mobile view. Here is my current logic: <div class="row"> <div *ngFor="let col of [1, ...

Step-by-Step Guide: Building a Reusable Component for Angular Material Data Table in Angular 5

I have multiple components that display data in a tabular format. I am looking to refactor the code into a reusable data table component so that other components can utilize it instead of duplicating the table in each component. However, I am unsure how ...

Are the Angular2 Material components able to work with previous versions?

For instance, I am currently utilizing Angular2 Material version 5.0.0-rc0. Suddenly, the 5.0.0-rc1 has been released with bug fixes that are essential for me. Is it safe to upgrade the component using npm install --save @angular/material@latest @angula ...

When attempting to test the service, an error occurred stating "subscribe is not a

Currently, I am working on writing a Jasmine test for testing service calls in Angular. To spy on the service, I have used jasmine.createSpyObj. However, I encountered an error message: this.agreementsService.getOutstandingAgreements(...).subscribe is not ...

Show refined information upon form submission or click

I am facing a challenge with implementing filtering functionality in an input box within a form in Angular 12. Despite my efforts, I have been unable to get the pipe working correctly in the component and consequently in the view. HTML ...

Angular 2: Toggle multiple checkboxes with a single click

I am faced with a scenario where I have 5 checkboxes implemented as shown below <input type="checkbox" [checked]="chk1" (change)="chk1 = !chk1" />chk1 &nbsp; <input type="checkbox" [checked]="chk2" (change)="chk2 = !chk2" />chk2 &nbsp; ...

Maximizing Jest's potential with multiple presets in a single configuration file/setup

Currently, the project I am working on has Jest configured and testing is functioning correctly. Here is a glimpse of the existing jest.config.js file; const ignores = [...]; const coverageIgnores = [...]; module.exports = { roots: ['<rootDir&g ...

Combine objects by selecting attributes from multiple objects

declare type A = {type: 'TypeA', attr1: string} declare type B = {type: 'TypeB', attr2: string} declare type U = A | B When I use type X = Pick<U, 'type'>, I get: { type: 'TypeA' | 'TypeB' } But I a ...

What is the reason for the removal of the `?` decorator in this mapped type? Are there alternative methods to achieve a similar outcome without eliminating it

Challenge In the process of creating a mapped type that excludes properties of type Function, we encountered an issue. Our current method not only eliminates functions but also strips away the optional decorator (?) from the mapped properties. Scenario ...

What is the best method to retrieve HTTP headers from the backend and simultaneously send HTTP parameters to it in ASP.NET Core and Angular?

I am currently working with Angular 15 and ASP.NET Core 5. The backend retrieves paged items based on the parameters pageSize and pageIndex. Once the action method receives the pageSize and pageIndex parameters, it sends both the paged items and the total ...