6

In a single angular component I wish have a print button which when the user clicks, will print a single div from my component's template.

I know this answer works, I've tried it. But I do not like how I need to reapply all styles or rewrite all the styles in the <style> head tags.

I really like this answer but I can't get it to work. I think it might have something to do with how classes are renamed after the app has been served/built.

This is how I've implemented the above answer but can't get it to work.

component.ts

onPrint() {
  window.print();
}

component.html

<div class="print">
  <button (click)="onPrint()">Print</button>
  all the stuffs I want to print
</div>

component.scss

@media print {
  :not(.print) {
    display: none !important;
  }
}

How can I get the above answer to work resulting as little code as possible, and retaining the styles applied to the front-end?

I realize how similar the question is to this one but this question was asked almost two years ago and with regards to angular 2. Not quite sure how different it is with regards to angular 6.

10
  • Can you show what you tried for the 2nd solution that you say isn't working? Which file did you add the style to? Commented Sep 28, 2018 at 19:37
  • sure! I've added it to my question. Commented Sep 28, 2018 at 19:42
  • Seems to work when I try it on StackBlitz / Chrome stackblitz.com/edit/angular-rfy6cj Commented Sep 28, 2018 at 19:46
  • For whatever reason it seems to print everything except my div class="print" element. Commented Sep 28, 2018 at 19:51
  • When I try that Stackblitz, the only bit that shows in the print preview is all the stuffs I want to print Commented Sep 28, 2018 at 19:52

4 Answers 4

5

The styles in the component CSS will only apply to that individual component, which is why the parent component mat tabs are still showing.

As an alternative, you can add the styles into style.css / styles.scss. The problem with this is that the parent DOM elements (such as body) will be set to display: none as well, so nothing will be visible.

You can instead try using visibility in styles.css like so:

@media print {
  :not(.printMe) {
    visibility: hidden;
  }
}

@media print {
  .printMe {
    visibility: visible
  }
}

Depending on your use case, this may help, although the hidden elements will still take up space on the page.

Here is a fork of the StackBlitz to demonstrate

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

1 Comment

I tried to add a table and it doesn't work, any idea? stackblitz.com/edit/angular-pmysdr-svmhde?file=app/print-me/…
0

A simple solution might be to display the div over the page content:

@media print {
 .print {
    position: fixed;

    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
  }
}

1 Comment

This works great for dialogs, as long as the dialog isn't larger than a single page.
0
<div [AppendToPrint]="true">
</div>

each element have AppendToPrint directive will show in print window after call this function

window.print();

@Directive({
  selector: '[AppendToPrint]'
})
export class AppendToPrintDirective implements AfterViewInit {

  private elementIdToPrint: string = 'print';

  isPrinted: boolean = true;
  clone;

  @Input("AppendToPrint")
  set appendToPrint(value: boolean) {
    this.isPrinted = value;
  }


  constructor(private elRef: ElementRef) {
  }

  ngAfterViewInit(): void {
    
    this.cloneElement();

    if (document.getElementById(this.elementIdToPrint)) {

      document.getElementById(this.elementIdToPrint).appendChild(this.clone);
    }
  }
  
  cloneElement(): void {
    this.clone = this.elRef.nativeElement.cloneNode(true);
  }

  ngOnChanges() {
    if (this.isPrinted) {
      this.resetPrint();
    }
    else {
      this.cloneElement();
        document.getElementById(this.elementIdToPrint).innerHTML = '';
        document.getElementById(this.elementIdToPrint).appendChild(this.clone);
      }
  
  }

  //#region == private methods ==

  private resetPrint(): void {
    document.getElementById(this.elementIdToPrint).innerHTML = '';
    this.isPrinted = false;
  }

  ///#endregion
}

Comments

-1

The only way that worked for me was to hide all elements aside from the one I am printing. Copying the HTML into a new window (and similar solutions) didn't work for me because of style issues.

The following code requires jQuery to work.

print(triggerElement): void
{
    const toShow = this.hideParentSiblings($('#print-section'));
    $(triggerElement).hide();

    window.print();

    for (const e of toShow)
    {
        e.show();
    }

    $(triggerElement).show();
}

hideParentSiblings(element): any[]
{
    let parent;
    const toShow = [];

    while ((parent = element.parent()).length)
    {
        const visible = parent.siblings().find(':visible');
        toShow.push(visible);
        visible.hide();
        element = parent;
    }

    return toShow;
}

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.