1

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>

3 Answers 3

1

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();'>

Sign up to request clarification or add additional context in comments.

Comments

0

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();
            }

3 Comments

This is working but the css layout is lost for the entire print document preview. Have tried adding the styles in the component tag but it is still not working. How can I add the styles in it?
In your css - @media print { add your style here }
@VinayKaklotar This is working, but If I cancel from Print page it is not getting close that print page and not redirecting back.
0

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}
    ]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.