Javascript: Print a single element

2010-02-16 – 5:18pm

Sometimes, you’ll want to allow users the ability to print only a part of your page; for example, a table but not the various links around the page. It’s possible to use a printing stylesheet, but this can cause severe headaches when you need different parts printed at different times. Really, we want to be able to just say element.printElement(), and have it just work. That’s what the MooTools function below does. It’s loosely based around the concepts outlined at this website.

Element.implement({
	printElement: function(docTitle) {
		var strName = 'printer-' + (new Date()).getTime();
		var styles = [];
		$$('link[type=text/css]').each(function(style) {
			styles.push('<link rel="stylesheet" type="text/css" href="' + style.get('href') + '"/>');
		});
		var title = docTitle || document.title;
		var that = this.getParent();
		var iframe = new IFrame({
			name: strName,
			styles: {
				width: 1,
				height: 1,
				position: 'absolute',
				left: -9999
			},
			events: {
				load: function() {
					var doc = window.frames[strName].document,
							win = window.frames[strName],
					f = function() {
						if (!doc.head) {
							f.delay(10);
							return;
						}

						// We need to delay printing so that styles are applied.
						(function() {
							doc.title = title;
							// IE7 won't let us adopt() here for some reason, and we can't do anything to the head.
							doc.body.innerHTML = styles.join('') + that.innerHTML;
							(function() {
								win.focus(); // IE needs the window to be focused.
								win.print();
							}).delay(100);
						}).delay(200);
					};
					f();
				}
			}
		}).inject($(document.body));
		(function() {
			iframe.dispose();
		}).delay(30000);
	}
});
2010-02-17 – 7:37 pm

nice! A question about ie needing the div to be focussed… Is it possible for the focus to be lost before the printing starts? Is there a mechanism to prevent focus stealing? Also, can one set the visibility on the iframe to make it invisible (yes, 1×1 is small, but still…) – or could one apply a z-index to make it appear.

Just thinking aloud here – these are tiny niggles. :-)

2010-02-18 – 6:23 pm

Hi Nick,

Focussing the iframe and then printing it *should* happen consecutively and nearly instantaneously. I suppose that it’s possible (although highly unlikely) that the user could transfer focus to something else between the two operations… Unfortunately, there’s no way to make the two operations atomic.

The iframe will be invisible by virtue of the fact that it’s 9999px to the left of the viewport. :)

Niki
2011-09-04 – 8:04 pm

Hi Barry!
I really like your code here, but it doesn’t work for me. It seems like there is a problem with line 19:
Object [object HTMLBodyElement] has no method ‘adopt’
Which version of Mootools are you using?

And i have one little question: Is it possible to clone the stuff into the Iframe?

Anyway, great script!

Niklas

2011-09-05 – 9:45 am

Hi Niki!

Hmm… This code has suffered from bitrot. :) I think I was using MooTools 1.2 at the time, which automatically MooTools-ified the iframe. I’ve updated the code in the post so that it now works correctly. Plus, it supports styles and is a little bit more robust. Let me know if this works for you!

Add your voice