2

I am grabbing dynamic data from my view or HTML placing it on my page so I can view the print out of said data. I have to use this method because I am creating my own print page with this dynamic data on it. The method that I am using grabs the first initial value and not the latest updated DOM. If I remove the .innerHTML I am able to see the dynamic data, however unsure if there's a way to get that data without .innerHTML.

TS

click(data){
this.newData = data
let printContents, popupWin;
    if(document.getElementById('print-section') != null){
      printContents = document.getElementById('print-section').innerHTML;
      popupWin = window.open('', '_blank', 'top=0,left=0,height=100%,width=auto');
      popupWin.document.open();
      popupWin.document.write(`
        <html>
          <head>
            <title>Print tab</title>
            <style>
            //........Customized style.......
            </style>
          </head>
          <body onload="window.print();window.close()">${printContents}</body>
        </html>`
      );
      popupWin.document.close();
    }

}

HTML

<div id="print-section" style="display:none">
        <div>
            <p>{{newData.id}}</p>
        </div>
 </div>
userlkjsflkdsvm
  • 961
  • 1
  • 21
  • 53

2 Answers2

2

You get the old content of the element because Angular's change detection mechanism did not update the DOM between the change to this.newData and the statement where you get the content of the div. The HTML output will be updated only after the current execution cycle.

You can force change detection with several techniques (see this answer). One of them is by calling ChangeDetector.detectChanges().

By the way, Angular's way to access DOM elements in code is with @ViewChild(varname) and template reference variables, instead of calling document.getElementById.

<div #printSection style="display:none">
  <div>
    <p>{{newData.id}}</p>
  </div>
</div>
import { Component, ViewChild, ElementRef, ChangeDetectorRef } from '@angular/core';

export class MyComponent {

  @ViewChild("printSection") printSectionRef: ElementRef;

  constructor(private changeDetector: ChangeDetectorRef) {
  }

  click(data) {
    this.newData = data
    this.changeDetector.detectChanges(); // Trigger change detection
    let printContents, popupWin;
    if (this.printSectionRef && this.printSectionRef.nativeElement){
      printContents = this.printSectionRef.nativeElement.innerHTML;
      ...
    }
  } 
}
ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
2

I recomment using ViewChild: Child components in our view can be accessed from our parent component easily with @ViewChild.

<div id="print-section" #printContainer style="display:none">
        <div>
            <p>{{newData.id}}</p>
        </div>
</div>

In component:

export class MyComponent{
  @ViewChild('printContainer') private printContainer: ElementRef; //import ElementRef
  constructor() {
  }

}

click method:

click(data){
this.newData = data
let printContents, popupWin;
    if(document.getElementById('print-section') != null){
      printContents = this.printContainer.nativeElement.innerHTML;

      // rest all remains same
    }

}

Also check this very similar question on how to perform DOM manipulation in Angular Components!

Peter
  • 10,492
  • 21
  • 82
  • 132