Reputation: 385
I am trying to implement a print functionality within my invoicing app, however, the print function I have only works for me once-that is, on the first click only. When I try to click again the click function is not triggered. And when I check my console.log, the following is error is thrown: ERROR TypeError: Cannot read property 'postMessage' of null
Here is what i have tried:
printInvoice() {
const printContents = document.getElementById('print-index-invoice').innerHTML;
const originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
<div class="modal fade" id="modalIndexInvoicePreview" tabindex="-1" role="dialog">
<button type="submit" class="btn btn-info btn-lg mt-2 position-absolute" (click)="printInvoice()">
<i class="fa fa-print icon-print"></i>Print</button>
<div class="modal-dialog modalContent">
<div class="modal-content modalIndexInvoicePreview" id="print-index-invoice">
<div class="modal-header div-logo">
<img class="logo-invoice" [src]="logoUrl">
<div>
<b>Invoice|Receipt|Attachment</b>
</div>
</div>
</div>
</div>
</div>
Upvotes: 1
Views: 18881
Reputation: 57
do it in a clean way and can add CSS and data to print page
//inside component where print button event triggered
PrintTransformerResult(): void {
// const transformerPanels = this.transformer;
this.printService.printDocument('T146', this.transformer);
}
//inside service
printDocument(documentName: string, documentData: any): void {
this.router.navigate(['/', { outlets: { print: ['print', {queryParams: JSON.stringify(documentData)}]}}]);
}
//inside print layout component.ts
export class PrintLayoutComponent implements OnInit {
invoiceIds: any;
data: any;
constructor(route: ActivatedRoute,
private router: Router,
private printService: PrintService) {
this.invoiceIds = route.snapshot.paramMap;
}
ngOnInit(): void {
console.log('xsssdsd' + JSON.stringify(this.invoiceIds));
this.data= JSON.parse(this.invoiceIds.params.queryParams);
setTimeout(() => {
window.print();
this.router.navigate([{ outlets: { print: null }}]);
}, 2000);
}
}
//inside print layout component.html
<div class="color-black font-18 ml-auto mb-10 text-center">
<span class="font-w9">{{data?.customer_name}}</span>
<span class="opacity-4 font-14 pl-4"><b>{{data?.object_id}}</b></span>
</div>
<div>
<span class="color-black2 font-16 width-full font-w9">T146 Input P146-1 : </span> <span class="ml-15">{{data?.modified_on}}</span>
<div class="mt-10">
Identification: {{data?.name}}
</div>
</div>
<-- custome tag, passing data -->
<div class="height-full" style="height: 100%;">
<app-t146-panel1-view [data]="data">
</app-t146-panel1-view>
</div>
// inside app component html
<router-outlet></router-outlet>
<router-outlet name="print"></router-outlet>
//inside routing module.ts
const appRoutes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'print', outlet: 'print', component: PrintLayoutComponent}
]
Upvotes: 0
Reputation: 1571
There are 2 ways to achieve the print functionality. First is you can utilize CSS media which will allow you to use media as "print".
The second option is to attach CSS to your print section part. You can easily enable media to "print while" attaching the external stylesheet to your print module. For now, I have enabled the bootstrap in the print module. You can use your own stylesheet in place of the bootstrap.
Visit jsfiddle.net/rdtzvf2c/1/
As you can see in the result, the top text and image are being pulled in the center which is happening through the bootstrap CSS applied dynamically while printing the div.
Do let me know in case of any other help.
function printDiv() {
var divToPrint = document.getElementById('print-index-invoice');
var newWin = window.open('', 'Print-Window');
newWin.document.open();
newWin.document.write('<html><link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css" media="print"/><body onload="window.print()">' + divToPrint.innerHTML + '</body></html>');
newWin.document.close();
setTimeout(function() {
newWin.close();
}, 10);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="modal-content modalIndexInvoicePreview" id="print-index-invoice">
<div class="container col-md-12">
<div class="text-center">
This is right aligned!
<img src="https://www.gstatic.com/webp/gallery3/1.png" class=" rounded mx-auto d-block" alt="...">
</div>
</div>
<div class="modal-header div-logo">
<div>
<b>Invoice|Receipt|Attachment</b>
</div>
</div>
</div>
<input type='button' id='btn' value='Print' onclick='printDiv();'>
Upvotes: 1
Reputation: 424
Try this
printInvoice() {
var divToPrint = document.getElementById('print-index-invoice');
var newWin = window.open('', 'Print-Window', 'width=1200,height=700');
newWin.document.open();
newWin.document.write('<html><head><link href="app/assets/css/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/><link href="app/assets/css/print.css" rel="stylesheet" type="text/css"/><style></style> </head><body onload="window.print()">' + divToPrint.innerHTML + '</body></html>');
newWin.document.title = 'Your PDF Title';
newWin.document.close();
}
Upvotes: 0