Is there an Angular way of printing a div from a HTML page?
Solution 1
I have created a simple directive for printing div contents using the iframe technique. It's a bit hackish, but works very well. there is no better way to do it in my opinion. The directive script is:
'use strict';
angular.module('yourAppNameHere').directive('printDiv', function () {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', function(evt){
evt.preventDefault();
PrintElem(attrs.printDiv);
});
function PrintElem(elem)
{
PrintWithIframe($(elem).html());
}
function PrintWithIframe(data)
{
if ($('iframe#printf').size() == 0) {
$('html').append('<iframe id="printf" name="printf"></iframe>'); // an iFrame is added to the html content, then your div's contents are added to it and the iFrame's content is printed
var mywindow = window.frames["printf"];
mywindow.document.write('<html><head><title></title><style>@page {margin: 25mm 0mm 25mm 5mm}</style>' // Your styles here, I needed the margins set up like this
+ '</head><body><div>'
+ data
+ '</div></body></html>');
$(mywindow.document).ready(function(){
mywindow.print();
setTimeout(function(){
$('iframe#printf').remove();
},
2000); // The iFrame is removed 2 seconds after print() is executed, which is enough for me, but you can play around with the value
});
}
return true;
}
}
};
});
In your template you mark the print button like this:
<a href="#" print-div=".css-selector-of-the-div-you-want-to-print">Print!</a>
And that's it, it should work. The hackish part is that the iFrame is removed after a certain number of miliseconds as there is no cross-browser way to detect the end of the print execution, so you guestimate how much time would be needed for it to run.
You may need to include jQuery for it to work, I'm not sure as I almost never work without it. I added some inline comments to make things clearer. I used some code from this answer that uses a popup to print div content (but outside of Angular.js). Maybe you'll like that approach more.
Solution 2
I needed this to work in IE8+
'use strict';
angular
.module('print-div', [])
.directive('printDiv', function () {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var iframe;
var elementToPrint = document.querySelector(attrs.printDiv);
if (!window.frames["print-frame"]) {
var elm = document.createElement('iframe');
elm.setAttribute('id', 'print-frame');
elm.setAttribute('name', 'print-frame');
elm.setAttribute('style', 'display: none;');
document.body.appendChild(elm);
}
function write(value) {
var doc;
if (iframe.contentDocument) { // DOM
doc = iframe.contentDocument;
} else if (iframe.contentWindow) { // IE win
doc = iframe.contentWindow.document;
} else {
alert('Wonder what browser this is... ' + navigator.userAgent);
}
doc.write(value);
doc.close();
}
element.bind('click', function(event) {
iframe = document.getElementById('print-frame');
write(elementToPrint.innerHTML);
if (window.navigator.userAgent.indexOf ("MSIE") > 0) {
iframe.contentWindow.document.execCommand('print', false, null);
} else {
iframe.contentWindow.focus();
iframe.contentWindow.print();
}
});
}
};
});
Ionut Ursan
Updated on August 16, 2022Comments
-
Ionut Ursan almost 2 years
I have an html page using AngularJS, and I want to print a div from it. Is there an Angular way of doing it? .. or it`s just the classic javascript way below:
<script language="javascript" type="text/javascript"> function printDiv(divID) { //Get the HTML of div var divElements = document.getElementById(divID).innerHTML; //Get the HTML of whole page var oldPage = document.body.innerHTML; //Reset the page's HTML with div's HTML only document.body.innerHTML = "<html><head><title></title></head><body>" + divElements + "</body>"; //Print Page window.print(); //Restore orignal HTML document.body.innerHTML = oldPage; } </script>
If AngularJS doesn't have anything around this, can you suggest o way of doing it, without using JavaScript functions (ex: doc.getElementById() ).. an approach close to the AngularJS way ?
Thx,
-
Wanny Miarelli over 9 yearsi tried lots of directive around the Google. This is fair easy to use and does it work. Thank you.
-
Michelangelo about 9 yearsThis is a clean solution and does not require jQuery plugins! Thanks, really useful
-
Michelangelo about 9 years@MladenDanic Although I really like the solution, I can not seem to load external css styling sheets. I am forced to use the html styling tags. Any way around this problem? I have a lot of styling to do :)...It becomes messy fast.
-
Mladen Danic about 9 years@Mikey Did you load your stylesheet inside the iFrame? (where it says
// Your styles here, I needed the margins set up like this
) -
Michelangelo about 9 years@MladenDanic Yes I did something like this:
<html><head><title></title><link href="css/print.css" >
-
Michelangelo about 9 years@MladenDanic Also, another problem I encounterd is that it does not work in IE11. I tries to open an iframe but fails...So answer below is also true.
-
Michelangelo about 9 yearsI can't believe this. IE is always a pain. The first answer seemed to work untill I tested this in IE. Does this do job well? I mean no problems in other browsers?
-
Michelangelo about 9 years@MladenDanic I found a different solution which was much more work but delivers a nice PDF to the user.