0

i have an angular 4 app and i have a function to print a content. here is part of my ts file:

print(id) {
// console.log(temp)
this.templateservice.getTemplateById(id).subscribe(template => {
  if (!template.success) {
    this.snackbar.open(template.message, '', {
      duration: 2000,
      extraClasses: ['success-snackbar']
    });
  } else {
    let headContents, innerContents, signContents, popupWin;
    headContents = document.getElementById('head-section').innerHTML;
    innerContents = document.getElementById('inner-section').innerHTML;
    signContents = document.getElementById('sign-section').innerHTML;

    console.log(headContents);
    popupWin = window.open('', '_blank', 'top=0,left=0,height=100%,width=auto');
    console.log(popupWin)
    popupWin.document.open();
    popupWin.document.write('<html><head><style></style></head><body onload="window.print();window.close()"><p class="head">' + headContents + '</p> <p class="inner">' + innerContents + '</p> <p class="sign">' + signContents + '</p></body></html>');
    popupWin.document.close();
  }
});// end of subscribe
}//end of print

and this is my html file:

<md-tab>
          <ng-template md-tab-label>Outgoing Mail</ng-template>
          <md-card-content >
            <div fxLayout="column" fxLayoutAlign="center center" class="mt-1" >
              <div class="template" style="@page  {size: A4};width: 210mm;height: 297mm;border-width: 2px;border-style: solid;border-color: #e6e6e6;padding-top: 23mm;padding-left: 2cm;padding-right: 2.5cm;padding-bottom: 55mm">
                <p class="head" id="head-section" style="line-height: 1cm;padding-left: 152mm;">Mail Number: {{mail_number}} <br> Date: {{created_at| date:'yyyy MMM dd'}}</p>
                <p class="inner" id="inner-section" style="max-height: 873px;line-height: 25px;word-spacing:1px;text-align: justify;padding-right: 20mm;padding-left: 25mm;padding-top: 21mm;padding-bottom: 5mm;white-space: pre-wrap; width: 166mm; word-wrap: break-word;">{{content}}</p>
                <p class="sign" id="sign-section" style="padding-left: 33mm;padding-right: 147mm ;padding-bottom: 70mm;line-height: 1cm;">Sincerely <br> {{sender}}</p>
              </div>
            </div>
          </md-card-content>
        </md-tab>

in this situation i get an error of "cannot read property document of undefined" and if i put the print codes out of the subscribe i can not access the template that is returned by the service! when i write console.log(headContents) i get response. but when i do console.log(popupwin) i get the image bellow! the popupwin is null and i have an error about document

enter image description here

fariba.j
  • 1,737
  • 7
  • 23
  • 42

3 Answers3

1

getTemplateById is asynchronous. It is undefined because you log before that the observable is resolved. Do your stuff inside the subscribe.

data;

print(id) {
    this.templateService.getTemplateById(id).subscribe(temp => {
        if (!temp.success) {
        } else {
            this.data = temp;
            console.log(this.data);

            var printContents = document.getElementById(divName).innerHTML;
            var popupWin = window.open('', '_blank', 'width=300,height=300');
            popupWin.document.open();
            popupWin.document.write('<html><head><link rel="stylesheet" type="text/css" href="style.css" /></head><body onload="window.print()">' + printContents + '</body></html>');
            popupWin.document.close();
        }
    }
}
Alexandre Annic
  • 9,942
  • 5
  • 36
  • 50
0
this.templateService.getTemplateById(id).subscribe(temp => {
    if (!temp.success) {
        // err
    } else {
        this.data = temp;
    }
});
console.log(this.data);

You can always get the this.data out side of the scope , here only issue is you will not get it right after the code,

Because the getTemplateById is async code , so it will execute in some time before that your console log will be called.

Solution :

print(id){
    this.templateService.getTemplateById(id).subscribe(temp => {
        if (!temp.success) {
            // err
        } else {
            console.log(this.data);
            this.data = temp;
            var printContents = document.getElementById(divName).innerHTML;
            var popupWin = window.open('', '_blank', 'width=300,height=300');
            popupWin.document.open();
            popupWin.document.write('<html><head><link rel="stylesheet" type="text/css" href="style.css" /></head><body onload="window.print()">' + printContents + '</body></html>');
            popupWin.document.close();
        }
    });
}
Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
  • i told that i tried your solution but i got "cannot read property document of undefined" error! :( – fariba.j Jan 15 '18 at 18:33
  • @fariba.j, that's because of `divName`, you haven't defined it and trying to use it , so it gets nothing. Please put some id there and try again. – Vivek Doshi Jan 16 '18 at 03:49
  • i defined the divName in my html file – fariba.j Jan 16 '18 at 05:26
  • Will you please post whole code in question or share a link of file ? – Vivek Doshi Jan 16 '18 at 05:31
  • Are you facing still same error? please also post the outputs of the `console.log` . – Vivek Doshi Jan 16 '18 at 06:05
  • i post an image of chrome console! actually my print codes work out of the subscribe btu i need some data in template to use them in print codes – fariba.j Jan 16 '18 at 06:24
  • You are not able to getting the elements via document.getelementbyid , that's your issue , please try to configure the project on https://stackblitz.com/ , it will be very helpful. – Vivek Doshi Jan 16 '18 at 06:27
  • but the error is happening at line of "popupWin.document.open();" i can get the elements by their ID – fariba.j Jan 16 '18 at 06:31
  • Yes I know , you should not use this way , there are so many other ways of doing this, you can use simple modal for this and display data over there – Vivek Doshi Jan 16 '18 at 06:33
  • you know i think the error i happening when the browser blocks the popups. is there any way to open the popup window even if the browser blocks them? – fariba.j Jan 16 '18 at 09:02
0

Add .finally() to your Observable, Do this:

this.templateService.getTemplateById(id)
.finally(() => {
      console.log(this.data);
})
.subscribe(temp => {
    if (!temp.success) {
      // err
    } else {
      this.data = temp;
    }
  });
Nadhir Falta
  • 5,047
  • 2
  • 21
  • 43