0

I'm working on an Angular webpage which runs several fetch requests towards an API. Some of the results are displayed in sub-components, which are closed panels that may be opened by the user.

Currently, all fetch requests run when the page itself is loaded, but I'm changing them to run only when necessary. When a user opens a given panel, only then should the corresponding data be fetched.

For these panels, triggering the fetch requests when opened is the easy part. The difficult part comes when I wish to print the page.

The print view includes all data, including the ones in the panels (while the panel header and borders are hidden, using CSS @media print).

In order to get all the associated data, all fetch requests must have been executed before printing.

Ergo, we have two cases:

  • Fetch data when opening the associated panel
  • Fetch all data before printing

I'm struggling with the print case.

I'm trying to use HostListener, with the window.beforePrint event. Fetching data is currently built like this:

//Ideal place for @HostListener('window:beforeprint', [])
fetchDataIfNotYetExecuted() {  // Executed when opening panel
    if (!this.dataHasBeenLoaded) {
        console.log('Loading data');
        this.fetchData();
    }
}

fetchData() {
    this.myApi.fetchData().subscribe({
        next: response => {
            this.data = response.data;
            this.dataHasBeenLoaded = true;
            console.log('Data load complete');
        },
        error => {
            console.log(error);
        }
    })
}

MyApi is a service that runs HttpClient.get, which leads to use of Observables, Subscriptions with data-prosessing, storing, etc, etc.

I need all this to be done before the print preview opens, and yet, what I have here is asynchronous code.,

I have made an attempt with async/await:

@HostListener('window:beforeprint', [])
async fetchDataIfNotYetExecuted() {  
    if (!this.dataHasBeenLoaded) {
        console.log('Loading data');
        await this.fetchData();
    }
}

async fetchData() {
    try {
        const response = await firstValueFrom(this.myApi.fetchData());
        this.data = response.data;
        this.dataHasBeenLoaded = true;
        console.log('Data load complete');
    } catch(error) {
        console.log(error);
    }
}

Since async/await works with Promises, and not Observables, I have to convert the Observable into a Promise, using RxJs.firstValueFrom.

Unfortunately, I can't get this to work properly.

Whenever I hit the webpage's print button, or run CTRL + P, I get a print preview without the data, while I see simultaneously in the console window that the fetch method is running, (so, if I hit 'print' again without reloading the page, the data is there).

I need the fetch to be done before proceeding to the print preview.

What am I missing?

Darth_Sygnious
  • 528
  • 3
  • 7
  • 18
  • You load the data before the user clicks on the print button. You can't wait to show print preview, this functionality is built into the browser directly. So either you download the data when the tab is visible and have an incomplete print preview OR download all data initially and don't have an individual download for each tab view. – cloned Jul 07 '22 at 14:01
  • Suggestion on what you can do: Load all data initially and store it in localstorage. Then on multiple visits to the page load the data from localstorage instead of fetching it again. Only fetch it again if data has changed. – cloned Jul 07 '22 at 14:02
  • As an alternative you could add your own print button, first do all the data fetching and then call ```window.print()``` – Charlie V Jul 07 '22 at 18:04
  • Charlie V: I already have a print button for the web page, but I need to cover ctrl + p as well, since there likely will be users that prefer the keyboard shortcut instead. Thanks anyway. – Darth_Sygnious Jul 08 '22 at 11:07

0 Answers0