ngx-print icon indicating copy to clipboard operation
ngx-print copied to clipboard

Allow printing from a service injected inside a component

Open vzakharov-rxnt opened this issue 3 years ago • 1 comments

Is your feature request related to a problem? Please describe. Can only print via directive which has to be applied on a button. This approach doesn't work with a custom button component or when using a 3rd party vendor library.

Describe the solution you'd like Add a PrintService injectable into component to trigger the print feature programmatically. Developer can then use a directive or service, depending on what fits their use case.

Describe alternatives you've considered Creating a dedicated print button component which will have to be restyled to match 3rd party vendor and style guidelines. Problem - code duplication.

Additional context N/A

vzakharov-rxnt avatar Apr 28 '22 11:04 vzakharov-rxnt

Here is an example of how the implementation might work (and it works, I tested). All params that I don't need were removed for quick delivery of this code. Comments were removed for brevity.

import { Injectable } from '@angular/core';

@Injectable()
export class NgxPrintService {
  private getElementTag(tag: keyof HTMLElementTagNameMap): string {
    const html: string[] = [];
    const elements = document.getElementsByTagName(tag);
    for (let index = 0; index < elements.length; index++) {
      html.push(elements[index].outerHTML);
    }
    return html.join('\r\n');
  }

  private getFormData(data: any) {
    for (var i = 0; i < data.length; i++) {
      data[i].defaultValue = data[i].value;
      if(data[i].checked) {
        data[i].defaultChecked = true;
      }
    }
  }

  private getHtmlContents(printSectionId: string) {
    let printContents = document.getElementById(printSectionId);
    let innards = printContents?.getElementsByTagName('input');
    if (innards) { // prevents error when print id was not found in the markup, will print "undefined" in this case
      this.getFormData(innards);
    }

    let txt = printContents?.getElementsByTagName('textarea');
    if (txt) {
      this.getFormData(txt);
    }

    return printContents?.innerHTML;
  }

  public print(printOptions: IPrintOptions): void {
    let printContents, popupWin, styles = '', links = '';
    const baseTag = this.getElementTag('base');

    if(printOptions.useExistingCss) {
      styles = this.getElementTag('style');
      links = this.getElementTag('link');
    }

    printContents = this.getHtmlContents(printOptions.printSectionId);
    popupWin = window.open("", "_blank", "top=0,left=0,height=auto,width=auto");
    if (!popupWin) {
      return;
    }

    popupWin.document.open();
    popupWin.document.write(`
      <html>
        <head>
          <title>${printOptions.printTitle ? printOptions.printTitle : ""}</title>
          ${baseTag}
          ${styles}
          ${links}
        </head>
        <body>
          ${printContents}
          <script defer>
            function triggerPrint(event) {
              window.removeEventListener('load', triggerPrint, false);
              setTimeout(function() {
                closeWindow(window.print());
              }, ${printOptions.printDelay});
            }
            function closeWindow(){
                window.close();
            }
            window.addEventListener('load', triggerPrint, false);
          </script>
        </body>
      </html>`);
    popupWin.document.close();
  }
}

export interface IPrintOptions {
  printSectionId: string;
  printTitle?: string;
  useExistingCss: boolean;
  printDelay: number;
}

Usage in a service or component via injection:

constructor(
  private printService: NgxPrintService,
) { }

print(printId: string) {
  this.printService.print({
    printDelay: 0,
    printSectionId: printId,
    useExistingCss: true,
  });
}

This works in Angular 13 to print a 3rd party vendor grid component using a customized 3rd party vendor button as a trigger.

"dependencies": {
  "@angular/animations": "13.3.3",
  "@angular/cdk": "13.3.3",
  "@angular/common": "13.3.3",
  "@angular/compiler": "13.3.3",
  "@angular/core": "13.3.3",
  "@angular/forms": "13.3.3",
  "@angular/platform-browser": "13.3.3",
  "@angular/platform-browser-dynamic": "13.3.3",
  "@angular/router": "13.3.3",

vzakharov-rxnt avatar Apr 28 '22 12:04 vzakharov-rxnt

This has been added in version 1.5.0

Core121 avatar Dec 04 '23 01:12 Core121