ngx-print
ngx-print copied to clipboard
Allow printing from a service injected inside a component
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
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",
This has been added in version 1.5.0