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?