Keywords: IE, iframes, printing
First I should admit that I don’t think of myself primarily as a frontend web developer. I’ve always thought of myself as an enterprise architect first, and a backend programmer second. I have no stake in the debates over liquid design versus tables, or over the inherent evilness of frames and iframes. But sometimes, like today, I have to wade right in. Briefly, I have a web application which allows users to build an HTML report from various dynamically generated ASP.Net forms, and users have the ability to upload attachments to the report. The attachments are primarily Microsoft Office documents with a few JPEGS and plain text thrown in.
So naturally the users want everything to display inline and print from a single button.
I can (thankfully) make a few simplifying assumptions: I am working with ASP.Net 2.0 in an inernal environment where I can assume everyone is using IE6.0. My first approach was to look into converting Word and Excel on the fly into text or HTML. This would allow content to be displayed inline and print from the familiar Print function in the browser. However, as I found out previously, using COM Interop to do conversions on the server is neither supported nor very stable. Using client side COM Interop seemed promising, but the early results were mixed as I didn’t like the formats and it seemed like it was the start of a slippery slope of endless tweaking. My second approach was to display the attachments in IFrames, with printing handled by my nemesis, Javascript. Being a pure “web” solution, I was less familiar with the technical challenges, but I learned quickly this afternoon.
Implementing this solution is easy using iframes. Here is a sketch for a sample report with two attachments. (In the following, ServeFile.ashx is n ASP.Net web handler that serves files, but you could replace it with whatever URL suits you on your domain.)
<html>
<head>
<title>Example Report</title>
<script type="text/javascript">
function printall() {
window.print();
for (var i=0; i<window.frames.length; i++) {
window.frames[i].focus();
window.frames[i].print();
}
}
</script>
</head>
<body>
<input type="submit" value="Print All"
onclick="javascript:printall()"
/>
<p>Hi! I'm a report!</p>
<iframe id="frame1" src="http://myserver.mydomain.com/ServeFile.ashx?FileID=1"></iframe>
<iframe id="frame2" src="http://myserver.mydomain.com/ServeFile.ashx?FileID=2"></iframe>
</body>
</html>
Two and a half comments. First, you’ll want to watch out for “Access Denied” javascript errors if you try to print iframes displaying content from other sites. This is denied to prevent cross site scripting attacks. Not a problem if you’re operating within a single domain. Second, the print job needs to know which iframe to print, so don’t forget to give the iframe focus before printing it. (Second and a half: I closed the iframe tag with a </iframe> instead of making it an empty tag on purpose. Necessary and truly goofy. See also this page.)
So what do you get when you display this page in IE6 and click the “Print All” button? I got a few print dialogs to which I answered “Print”, I got the “H! I’m a report!” page, and I got the contents of the second iframe, iframe #2, twice. Nothing from iframe #1. Interesting.
It took an hour and a ream of paper, but it turns out that the problem is that the iframe you want to print has to be in focus when you hit the print button on the print dialog. (90% of the forums I sampled that suggested something along the lines of the above stopped at one iframe. Hmmmm.) It turns out that the following solution does work:
<html>
<head>
<title>Example Report</title>
<script type="text/javascript">
function printall() {
window.print();
for (var i=0; i<window.frames.length; i++) {
alert('Click here AFTER you have sent document ' + (i+1) + ' to the printer.');
window.frames[i].focus();
window.frames[i].print();
}
}
</script>
</head>
<body>
<input type="submit" value="Print All"
onclick="javascript:printall()"
/>
<p>Hi! I'm a report!</p>
<iframe id="frame1" src="http://myserver.mydomain.com/ServeFile.ashx?FileID=1"></iframe>
<iframe id="frame2" src="http://myserver.mydomain.com/ServeFile.ashx?FileID=2"></iframe>
</body>
</html>
How did I find that out? I was a desperate man, grasping at straws. Also, the backend developer in me was suspicious of the “focus”: if I’m giving an iframe object to its print() method through the implicit “zeroth” argument, why does it need to have focus()? Unless print is not a really method of iframe, iframe.print() is just fake javascript sugar on top of an overload of window.print(), and the window overload doesn’t actually take iframe as an argument. Perhaps because of cross site scripting, or perhaps because of bad beans. It’s just a guess. Whatever is going on, I’m sure there’s a good reason, iframes are evil, and it will be all fixed in IE7…
Of course, this solution is silly, like a poor Dickensian cobbler using one shoe to pound nails into the sole of another shoe. So I ended up including good old empty hyperlinks to content alongside iframes displaying the same content, and I ask my users to check the “Print All Linked Documents” option in their print dialog options tab. I think this may only be an option in IE6, unfortunately.
By the way, this why I’m not a frontend developer.
I’m running into the same problem with IE 7.0 and have also resorted to “Print All Linked Documents”. Unfortunately, when I do that, not all of my linked documents print. Text and HTML are fine, but Word, Excel and PDFs print out blank. Have you run into this? And if so, do you know how to fix it?
Thanks :)
Yes, I’ve run into that. Unfortunately, I don’t know of any easy ways to fix it: the problem with office docs appears to be in between IE and Office because the COM object is not being opened by IE with the appropriate flags to suppress dialog boxes. Eventually, I solved the problem by creating a desktop application that would print the web page using IE automation, find all of the attachments, and then download each attachment in turn and print it. It works beautifully, but then you have to distribute a desktop app. Not a huge problem for me since this was all internal work, but on the internet you’d have to distribute that as an ActiveX control.
I’ll post the code for that tonight.
5pThank’s.4r I compleatly disagree with last post . uqq
паркет и ламинат 0l
Not sure what you’re objecting to. Using the above method, we observe that certain MS Office files can halt the automatic printing process in iframes in IE. When opening, printing and closing these problem files manually, we would often get a dialog box. When we fixed the problem with the dialog box, presto, the automatic process would not halt. So it seems to me that the problem is with a dialog box. I know for a fact that I can turn off the dialog boxes from my own COM programs – I’ve never had a problem printing such problem MS Office files using COM directly. So my guess is that IE doesn’t (or can’t) turn them all off when IE is printing one from an iFrame.
FWIW, I found that while a Desktop application worked well in that regard, the users were still asking for the ability to print double-sided, 4 per page and whatnot. Since the desktop application was printing documents out one by one (without merging them), this was difficult. Instead, we now use Open Office to convert all documents to PDF, and then we use Ghostview to merge all results into a single PDF document.
The general problem is that the users are requesting functionality that cannot be easily implemented; namely, the ability to combine multiple documents in possibly multiple formats inside of a web form – and print them all in one button click. I’d love to push back and standardize the formats they use, but some of our documents come from customers anyway.
Have you looked at the onbeforeprint and onafterprint IE specific events?
FWIW, I believe “ламинат” is a spam-bot, and just wants some of your google juice.