Convert HTML to Print preview PDF on angularjs and typescript, using SCSS

html to pdf illustration (https://dhwwtar19mmjy.cloudfront.net/lightpdf/wp-content/uploads/2018/07/convert-html-to-pdf-online.jpg.webp)

by @https://github.com/Michaelzvu

Html example to integrate the directive

<ng-print print-element-id=”$ctrl.printElementId”
on-before-print=”$ctrl.onBeforePrint()”></ng-print>
<div id="{{$ctrl.printElementId}}" ng-if="$ctrl.isReady">
....your print content...
</div>

scss part

@media print {

@page {
size: A4 landscape;
size: auto; /* auto is the initial value */
/* this affects the margin in the printer settings */
margin: 25mm 25mm 25mm 25mm;
}

body {
overflow: visible;
/* this affects the margin on the content before sending to printer */
margin: 0px;
}

avr-dimension-view-header td {
box-sizing: border-box;
}
}

Type script part

import { OnInit, Component, Output, Input } from 'angular-ts-decorators';
import './ngPrint.scss';

const autobind = libavrui.decorators.autobind;

/**
* @ngdoc component
* @param NgPrint
* @internal
*/
@Component({
selector: 'ng-print',
styles: [require('./ngPrint.scss')]
})
export class NgPrint implements OnInit {
@Input() printElementId: string;
@Input() bodyClass: string;
@Input() copyStyles: boolean;
@Input() content: () => void;
@Input() pageStyle: string;
@Output() onBeforePrint: () => void;
@Output() onAfterPrint: () => void;

private linkTotal = 0;
private linksLoaded: any = [];
private linksErrored: any = [];

/*@ngInject*/
constructor(private $scope: ng.IScope,
private $timeout: ng.ITimeoutService) {}

public ngOnInit() {
this.copyStyles = this.copyStyles || true;
this.bodyClass = this.bodyClass || '';
this.$scope.$on('ng-print.printPage', this.printPageChange);
}

@autobind
private printPageChange() {
if (!this.printElementId) {
throw new Error(`ng-print directive - print-element-id attribute is missing`);
}
const elemToPrint = document.getElementById(this.printElementId);

if (!elemToPrint) {
throw new Error(`ng-print directive - there isn't an element with the id: ${this.printElementId}`);
}
this.$timeout(() => this.handlePrint(elemToPrint));
}

private removeWindow(target: any) {
setTimeout(() => {
target.parentNode.removeChild(target);
}, 500);
}

private triggerPrint(target: any) {
if (this.onBeforePrint) {
this.onBeforePrint();
}

setTimeout(() => {
target.contentWindow.focus();
target.contentWindow.print();
this.removeWindow(target);

if (this.onAfterPrint) {
this.onAfterPrint();
}
}, 500);
}

private handlePrint(elemToPrint: any) {
const printWindow = document.createElement('iframe');
printWindow.style.position = 'absolute';
printWindow.style.top = '-1000px';
printWindow.style.left = '-1000px';

// TODO: Uncomment this line if you are going to use canvas on your page
// const contentNodes: any = elemToPrint;
const linkNodes = document.querySelectorAll('link[rel="stylesheet"]');

this.linkTotal = linkNodes.length || 0;
this.linksLoaded = [];
this.linksErrored = [];

const markLoaded = (linkNode: any, loaded: any) => {
if (loaded) {
this.linksLoaded.push(linkNode);
} else {
console.error(`'ng-print' was unable to load a link. It may be invalid.
'ng-print' will continue attempting
to print the page. The link the errored was:`, linkNode); // eslint-disable-line no-console
this.linksErrored.push(linkNode);
}

// We may have errors, but attempt to print anyways - maybe they are trivial and the user will
// be ok ignoring them
if (this.linksLoaded.length + this.linksErrored.length === this.linkTotal) {
this.triggerPrint(printWindow);
}
};

printWindow.onload = () => {
/* IE11 support */
if (window.navigator && window.navigator.userAgent.indexOf('Trident/7.0') > -1) {
printWindow.onload = null;
}

const domDoc = printWindow.contentDocument || printWindow.contentWindow.document;
// TODO: Uncomment this line if you are going to use canvas on your page
// const srcCanvasEls = [...contentNodes.querySelectorAll('canvas')];

domDoc.open();
domDoc.write(elemToPrint.outerHTML);
domDoc.close();

/* remove date/time from top */
const defaultPageStyle = this.pageStyle === undefined
? '@page { size: auto; margin: 0mm; } @media print { body { -webkit-print-color-adjust: exact; } }'
: this.pageStyle;

const styleEl = domDoc.createElement('style');
styleEl.appendChild(domDoc.createTextNode(defaultPageStyle));
domDoc.head.appendChild(styleEl);

if (this.bodyClass.length) {
domDoc.body.classList.add(this.bodyClass);
}

// TODO: Microsoft Edge doing problems with this line
// TODO: Uncomment this line if you are going to use canvas on your page
// const canvasEls: any = domDoc.querySelectorAll('canvas');
// [...canvasEls].forEach((node, index) => {
// node.getContext('2d').drawImage(srcCanvasEls[index], 0, 0);
// });

if (this.copyStyles !== false) {
const headEls: any = document.querySelectorAll('style, link[rel="stylesheet"]');

[...headEls].forEach((node, index) => {
if (node.tagName === 'STYLE') {
const newHeadEl = domDoc.createElement(node.tagName);

if (node.sheet) {
let styleCSS = '';

for (const rule of node.sheet.cssRules) {
styleCSS += `${rule.cssText}\r\n`;
}

newHeadEl.setAttribute('id', `ng-print-${index}`);
newHeadEl.appendChild(domDoc.createTextNode(styleCSS));
domDoc.head.appendChild(newHeadEl);
}
} else {
const attributes = [...node.attributes];

const hrefAttr = attributes.filter(attr => attr.nodeName === 'href');
const hasHref = hrefAttr.length ? !!hrefAttr[0].nodeValue : false;

// Many browsers will do all sorts of weird things if they encounter an empty `href`
// tag (which is invalid HTML). Some will attempt to load the current page. Some will
// attempt to load the page's parent directory. These problems can cause
// `ng-print` to stop without any error being thrown. To avoid such problems we
// simply do not attempt to load these links.
if (hasHref) {
const newHeadEl = domDoc.createElement(node.tagName);

attributes.forEach((attr) => {
newHeadEl.setAttribute(attr.nodeName, attr.nodeValue);
});

newHeadEl.onload = markLoaded.bind(null, newHeadEl, true);
newHeadEl.onerror = markLoaded.bind(null, newHeadEl, false);
domDoc.head.appendChild(newHeadEl);
} else {
console.warn(`'ng-print' encountered a <link> tag with an empty 'href' attribute.
In addition to being invalid HTML, this can cause problems in many browsers,
and so the <link> was not loaded. The <link> is:`, node); // eslint-disable-line no-console
markLoaded(node, true); // `true` because we've already shown a warning for this
}
}
});
}

if (this.linkTotal === 0 || this.copyStyles === false) {
this.triggerPrint(printWindow);
}
};

document.body.appendChild(printWindow);
}
}

--

--

--

Veteran Front end developer. Obsessing over ROI development. Addicted to online FPS. Rehabing from Hack and Slash.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

What your choice in psychoactive substances says about your favorite JS framework

An Oxymoron : Static Analysis of a Dynamic Language (Part 2)

class=“col-md-6” considered harmful

Commit frequently, push often

audio.play( )

🌐Our new website is live! (REAPIt.io)

How to: generate 2D matrix from an Array of random values with Javascript

Storybook 6.3 is live!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alexander Luria

Alexander Luria

Veteran Front end developer. Obsessing over ROI development. Addicted to online FPS. Rehabing from Hack and Slash.

More from Medium

Easy alternatives for Map and Set in a JavaScript-oriented front-end, back-end configuration

List animation in Ionic 6 & Angular

Article Preview Image

Authentication using the Amazon Cognito to an Angular application

How I improved nested arrays performance in our MongoDB