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,
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.
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();
}
});
}
};
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With