Ensure that Angular waits for the subscription to be completed before triggering the function to generate an Excel

I've encountered an issue with a function that generates an excel from an API request on my webpage. There's a download button that triggers the downloadCSV() function, which usually works fine except when I click it too quickly while navigating to the page.

Within the function, I subscribe to the data and populate an array used for generating the excel. Even if the array is empty, the excel still downloads immediately.

I'm considering two options:

1. Retrying the function if the excel turns out to be empty.

2. Waiting for the subscription to finish before executing.

downloadCSV (): void {
//list headers
const csvHeaders = [
 'bunch of headers'
];

//initiate array
const data: any[] = [];
//fetch names for each customer
this.nameService.getNames().subscribe({
  next: ({ names }) => {
    //for each customer, fetch details 
    names.forEach(name => {
      //get details
      this.nameService.getPersonalData(name.firstName).pipe(
        tap((data: Idata) => {
          data.push({
            'bunch of data points'
          });
        })
      ).subscribe(
        { error: (err) =>
        { console.error(err); } });
    });
  }
});
const filename = 'dataReport';
    this.generateCSV(data, filename, reportHeaders);

}

  generateCSV (data, filename, reportHeader): void {
    new ngxCsv(data, filename, { headers: reportHeader, showTitle: true, title: this.customerDetails });
  }

Essentially, the function involves fetching names, then using the first name to retrieve the desired data, and finally subscribing and generating an excel.

Currently, the excel instantly downloads without waiting for the data to be populated.

Answer №1

The optimal approach is to wait for all subscriptions to conclude before proceeding.

If your Excel sheet is empty, the cause could vary and needs to be addressed accordingly. Additionally, if you are dealing with large requests, it's unpredictable how many times you may need to retry. In most cases, random retries are not ideal.

In this scenario, utilizing the forkJoin operator from RxJS would be suitable.

Essentially, forkJoin merges all observables into one entity, resulting in a single subscription at the end (for all 'getPersonalData' requests).

This code snippet demonstrates the implementation:

this.nameService.getNames().subscribe({
      next: ({ names }) => {
        //for each customer list details
        forkJoin(
          names.map((name) => {
            //get details
            return this.nameService.getPersonalData(name.firstName)
              .pipe(
                 catchError((err) => {
                    console.error(err);
                 }));
          }),
        ).subscribe((datas: Idata[]) => {
          // Perform actions on datas before further processing
          this.generateCSV(datas, filename, reportHeaders);
        });
      },
    });

You should wait for all requests to emit values before executing your method.

PS: Some syntax mistakes might exist as I haven't tested the code

PS2: Remember to unsubscribe from all observables!

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

What is the best way to show summary calculations in the footer of a PrimeNG table?

I'm struggling to figure out how to create a summary function at the end of a PrimeNG p-table. I need to be able to calculate totals or minimum values for specific columns in the table based on the visible rows. My initial attempt involved trying to ...

Create an observable array that contains both outer and inner response properties within an Angular application

How can I create an Observable array in Angular by making API calls based on the response of another API call, which returns an array of elements? For example: queryThatReturnsArray().pipe( switchMap((outerResponse) => { return forkJoin(out ...

Facing problem with implementing NgMoudleFactoryLoader for lazy loading in Angular 8

A situation arose where I needed to lazy load a popups module outside of the regular router lazy-loading. In order to achieve this, I made the following adjustments: angular.json "architect": { "build": { ... "options": { ... "lazyM ...

"Implementing a Filter for Selecting Multiple Options in Ionic Framework

I need help with filtering books in an online library project using a modal page. The modal has 3 input fields for title, author, and year. How can I filter the books based on these inputs? Here is a snippet of my modal.html code: <ion-content pa ...

Issue when calling .create() method on Mongoose schema: "this expression is not callable" error in TypeScript

Encountering an error with the .create method on a mongoose model in Next JS while making a call in an API route. The get request is functioning properly... The structure: pages>API>task.tsx import dbConnect from "../../util/dbconnect"; im ...

Pattern matching to eliminate line breaks and tabs

Hey there, I'm working with a string: "BALCONI \n\n\t\t\t\t10-pack MixMax chocolade cakejes" and trying to tidy it up by removing unnecessary tabs and new lines. I attempted using .replace(/(\n\t)/g, '&apo ...

Customize back button functionality in Ionic 2

Is it possible to modify the behavior of the back button shown in this image? I would like to specify a custom destination or perform an action before navigating back, instead of simply returning to the previous page. https://i.stack.imgur.com/EI2Xi.png ...

Set up a custom key combination to easily toggle between HTML and TypeScript files that share the same name

Is it possible to set up a keyboard shortcut (e.g. Ctrl + `) to toggle between mypage.html and mypage.ts files? In my project, I have one HTML file and one TypeScript (TS) file with the same names. Ideally, I'd like to create a hotkey similar to F7 fo ...

What steps can I take to troubleshoot and repair my accordion feature within an Angular project?

As a newcomer to Angular, I recently attempted to create an accordion component but encountered unexpected behavior. Here is the HTML code for my attempt: <div class="faq-item-container"> <h1 class="mt-1 mb-5"><strong>Frequently A ...

Top tips for creating effective Angular 2 components

My application features a user object that stores and updates all user information using an observable provided by the userService. I am now contemplating the best practice for utilizing this user observable with components. One specific scenario involves ...

Tips for troubleshooting compile errors when updating an Angular project from version 6 to 7

I am currently working on upgrading my Angular 6 project to Angular 10, following the recommended approach of going through one major version at a time. Right now, I am in the process of updating it to version 7.3. Despite following the steps provided on u ...

"Error encountered while executing a code snippet using Navalia in TypeScript

I have been attempting to execute this code snippet from https://github.com/joelgriffith/navalia but despite my efforts, I have not been able to get it running smoothly without encountering errors: navaliatest.ts /// <reference path="typings.d.ts" /&g ...

Creating Unique Layouts for Specific Routes in Next.js App Router

Issue with Layout Configuration I am facing a challenge in creating a unique layout for the /api/auth/* routes without including the components CustomNavbar and Footer from the main RootLayout. Despite my attempts, the main layout continues to be displaye ...

An issue has occurred: Uncaught (in promise): NullInjectorError: R3InjectorError(AppModule)[NavbarComponent -> NavbarComponent

I've been working on implementing Google Auth login with Firebase, but I keep encountering an issue when trying to load another component or page after logging in. I've spent the entire day trying to debug this problem and it's really frustr ...

Is it feasible to utilize a single parent component with multiple unique child components in Angular 2?

Is it possible to create a parent component without specifying the child component? Typically, I would define a parent component and include the selector of the child component in the HTML file parent-component-1.html: //some logic <child-component-1 ...

RxJS emits an array of strings with a one second interval between each emission

Currently, my code is set up to transform an Observable<string[]> into an Observable<string>, emitting the values one second apart from each other. It's like a message ticker on a website. Here's how it works at the moment: const ...

How can we ensure file uploads are validated when using class-validator?

Recently, I've been utilizing the wonderful class-validator package to validate data. One specific validation task I'm working on is validating a file upload, ensuring that the file is not empty and ideally confirming that it is an image file. H ...

The MemoizedSelector cannot be assigned to a parameter of type 'string'

Currently, my setup involves Angular 6 and NgRX 6. The reducer implementation I have resembles the following - export interface IFlexBenefitTemplateState { original: IFlexBenefitTemplate; changes: IFlexBenefitTemplate; count: number; loading: boo ...

Angular's promise is incompatible with the type ts2322 and cannot be assigned

Struggling to implement a login feature in Angular, encountering an error related to promises: "Type 'Promise<ApiResponse<UserLogged> | undefined>' is not assignable to type 'Promise<ApiResponse<UserLogged>>&apos ...

Angular 2 GET request returns a 404 error

I have been attempting to reproduce the ngPrime datatable demo from this Github repository. Currently, I am working with the most recent version of Angular (4) and using angular-cli in development mode. Placing a JSON file into my app folder where the serv ...