Open Hypercubed opened 2 months ago
Tricky indeed. To be honest, I'm a clueless.
Esiest fix I can up with is to cachebust the viewer mjs file. Two lines changed:
const viewerPath = this.getPdfJsPath('viewer') + '?v=' + new Date().getTime();
and in createScriptElement
script.type = sourcePath.includes('.mjs') ? 'module' : 'text/javascript';
Not the best solutions... since it also bypasses the browser cache.
Guessing the better fix is to wrap these lines in a global function that gets called onload. https://github.com/stephanrauh/ngx-extended-pdf-viewer/blob/main/projects/ngx-extended-pdf-viewer/assets/viewer-4.5.713.mjs#L38804C1-L38812C31
~Something like this (untested):~
DOESN'T WORK
function ngxViewerFileHasBeenLoaded() {
const event = new CustomEvent('ngxViewerFileHasBeenLoaded', {
detail: {
PDFViewerApplication: __webpack_exports__.PDFViewerApplication,
PDFViewerApplicationConstants: __webpack_exports__.PDFViewerApplicationConstants,
PDFViewerApplicationOptions: __webpack_exports__.PDFViewerApplicationOptions,
webViewerLoad: __webpack_exports__.webViewerLoad,
},
});
document.dispatchEvent(event);
}
if (document.readyState === "interactive" || document.readyState === "complete") {
ngxViewerFileHasBeenLoaded();
} else {
document.addEventListener("DOMContentLoaded", ngxViewerFileHasBeenLoaded, true);
}
OK.. Here is the best I got:
In viewer.mjs
:
function ngxViewerFileHasBeenLoaded() {
const event = new CustomEvent('ngxViewerFileHasBeenLoaded', {
detail: {
PDFViewerApplication: __webpack_exports__.PDFViewerApplication,
PDFViewerApplicationConstants: __webpack_exports__.PDFViewerApplicationConstants,
PDFViewerApplicationOptions: __webpack_exports__.PDFViewerApplicationOptions,
webViewerLoad: __webpack_exports__.webViewerLoad,
},
});
document.dispatchEvent(event);
}
window.ngxViewerFileHasBeenLoaded = ngxViewerFileHasBeenLoaded;
In pdf-script-loader.service.ts#loadViewer
:
document.addEventListener('ngxViewerFileHasBeenLoaded', listener);
const script = this.createScriptElement(viewerPath);
script.onload = () => {
window.ngxViewerFileHasBeenLoaded();
};
document.getElementsByTagName('head')[0].appendChild(script);
Could bypass the ngxViewerFileHasBeenLoaded
altogether if ngxViewerFileHasBeenLoaded()
returns the details directly.
I can do a PR if you are happy with having ngxViewerFileHasBeenLoaded
as a global.
I think we need a solution that does not pollute the global namespace. The best solution would be to wrap the viewer file in an Angular component. Unfortunately, I haven't managed to do that yet.
In the long run, I'd like to be able to have multiple independent instances of the viewer simultaneously. It seems many developers need this feature, and https://pdfviewer.net/extended-pdf-viewer/side-by-side uses a very clumsy work-around.
Here is a tricky one.... I noticed that when running >v21, component tests started breaking. After quick a bit of investigation I'm pretty sure I've narrowed down the issue to the changes introduced in 21.0.0-alpha.0. Here is the breakdown:
21.0.0-alpha.0 introduces
PDFScriptLoaderService
which loads the pdfjs viewer inside theloadViewer
method. TheloadViewer
method relies on thengxViewerFileHasBeenLoaded
event being triggered when loading the viewermjs
file. This works fine on initial load since themjs
file includes the event trigger. However, in unit/component testing the Angular app is destroyed and thePDFScriptLoaderService#destroy
method is called to cleanup. The Angular app is then "rebooted" in the same window. But since the viewer is loaded as a module, it is not executed again (ES modules are loaded once and reused). ThengxViewerFileHasBeenLoaded
event is never triggered and therefore the pdfjs is never initailzed.Seams like we need a different way to trigger the listener inside
loadViewer
that doesn't rely on side effects inside the module.I've only seen this in testing; since a app usually has the same lifecycle as the document/window.