Printing on Android device with Angular

Viewed 142

I have an application where I need to print content that doesn't exist on the page but does exist in the angular template. In the template, I have a div with a click method that will accept an identifier, and then build an iframe based on the content of the id it received. The first snippet is what the clickable element looks like.

<div (click)="printButton('#printThis')" class="menu-item print-menu-item">Race {{ raceSelected?.raceNumber }}</div>

This code snippet is just a basic element with omitted private data. So it will just be an ng-template with an identifier and an iframe that I access from the method pasted below.

<ng-template #printThat>
    // content that I will print but not important for this question
</ng-template>

<ng-template #printThis>
    // content that I will print but not important for this question
</ng-template>

<iframe #iframe></iframe>

The last code snippet is the method on the component that builds the iframe and brings up the print dialog.

public async printButton(printMode: string): Promise<void> {
        let printTemplate;
        if (printMode === '#printThat') {
            await this.getAllRacesForPrint()
            printTemplate = this.printAll;
        } else if (printMode === '#printThis') {
            printTemplate = this.printSingleRace;
        }
        const iframe = this.iframe.nativeElement;
        this.portalHost = new DomPortalOutlet(
            iframe.contentDocument.body,
            this.componentFactoryResolver,
            this.appRef,
            this.injector
        );

        const portal = new TemplatePortal(
            printTemplate,
            this.viewContainerRef
        );

        // Attach portal to host
        this.portalHost.attach(portal);
        iframe.contentWindow.onafterprint = () => {
            iframe.contentDocument.body.innerHTML = '';
        };

        this._attachStyles(iframe.contentWindow);

        iframe.contentWindow.print();
    }

These two private functions are invoked in the method above to add the css to the iframe.

private _attachStyles(targetWindow: Window): void {
        // Copy styles from parent window
        document.querySelectorAll('style').forEach((htmlElement) => {
            targetWindow.document.head.appendChild(htmlElement.cloneNode(true));
        });
        // Copy stylesheet link from parent window.
        const styleSheetElement = this._getStyleSheetElement();
        targetWindow.document.head.appendChild(styleSheetElement);
    }

private _getStyleSheetElement(): HTMLLinkElement {
        const styleSheetElement = document.createElement('link');
        document.querySelectorAll('link').forEach((htmlElement) => {
            if (htmlElement.rel === 'stylesheet') {
                const absoluteUrl = new URL(htmlElement.href).href;
                styleSheetElement.rel = 'stylesheet';
                styleSheetElement.type = 'text/css';
                styleSheetElement.href = absoluteUrl;
            }
        });
        return styleSheetElement;
    }

This works perfectly on all devices without a problem EXCEPT Android devices. On Android, the print dialog box comes up but the page is blank and has no content. Are there any good solutions for printing for Android that do not require bringing in a package or am I missing something here?

0 Answers
Related