Geeks With Blogs
Lee Brandt's Blog You're only as smart as your last line of code

I didn’t leave work until 8PM this evening. I was wrestling with a JavaScript/JQuery problem and it became a personal battle to bend this application to my will. (Maybe in some future post I’ll talk about how horrible that is.) So I didn’t get it before I left, but I came home and started hitting it here on a test project. There seems like there are probably some scripting conflicts in our project (we have the JQuery stuff and prototype in there), so it didn’t take be but about a half-hour at home to come up with a working prototype. Then I fought with browser compatibilities a bit. But I thought I would post my solution here for two main reasons: There might be a better solution that eluded my Google-fu today, and if not, I may need to refer back to the solution in the future.

The Problem

The page I am working, needs to allow users to select their favorites from a list of item’s (via checkbox) and then print them. The approach I chose (Thanks Nidal!) was to load a page using an iframe and print the iframe. Easy, right? Not quite. The problem was not loading the iframe or getting all the checked items, it was actually printing the content in an iframe. At first, I thought I’d put a script on the iframe content page something like:

The Trial

   1: $(document).ready(function() { 
   2:   window.print(); 
   3: });

The Errors

No such luck. I did a little Google-ing (I mean.. um .. Bing-ing? Bang-ing?) and saw that most of the solutions for “print iframe JQuery JavaScript” were using some form of:

   1: window.frames['PrintFrame'].focus();
   2: window.frames['PrintFrame'].print();

A straight-up JavaScript solution. So I tried it. But my print() was happening so fast that my content in my iframe hadn’t loaded, so I kept printing blank pages. (NOTE: When developing something like this where you need to print, switch your default printer to Microsoft XPS Document Writer first. You’ll save on paper.) So i needed a way to make sure that the print didn’t get called until the iframe was loaded, and luckily JQuery has events to wire into:

   1: var frame = $("#PrintFrame")
   2: frame.load(function() {
   3:   window.frames['PrintFrame'].focus();
   4:   window.frames['PrintFrame'].print();
   6: });

Now you’ll notice the JQuery on the outside of the load call and the regular JavaScript call on the inside. For some reason, the calls to the frame object do not give me the object I need to call print(). Now this worked fine, with the exception that if I tried to unload the frame content (just for cleanliness sake) the load fires again. I had come across a Stack Overflow question that talked about a dynamic iframe, and it got me to thinking, “what about an iframe that I create programmatically, load, print and then destroy?” Which led me to this:

   1: $(document.createElement("iframe"))
   2: .attr('style', 'height:0px;width:0px;position:absolute;top:-500px;left:-500px;')
   3: .attr("id", "PrintFrame")
   4: .attr('name', 'PrintFrame')
   5: .attr('src', url)
   6: .prependTo("body")
   7:  
   8: var frame = $("#PrintFrame")
   9: frame.load(function() {
  10:   window.frames['PrintFrame'].focus();
  11:   window.frames['PrintFrame'].print();
  13: });

 

My Solution (‘til a better one comes along)

Firefox, using this solution created and destroyed the iframe so fast it was unable to print, so i changed it slightly:

   1: $(document.createElement("iframe"))
   2: .attr('style', 'height:0px;width:0px;position:absolute;top:-500px;left:-500px;')
   3: .attr("id", "PrintFrame")
   4: .attr('name', 'PrintFrame')
   5: .attr('src', url)
   6: .prependTo("body")
   7:  
   8: var frame = $("#PrintFrame")
   9: frame.load(function() {
  10:   window.frames['PrintFrame'].focus();
  11:   window.frames['PrintFrame'].print();
  12:   setTimeout(function() { frame.remove(); }, 1000);
  13: });

This worked marvelously in IE, and printed and destroyed as it should in Firefox, but I noticed that Firefox kept spinning after the create/print/destroy sequence was over. If you tried to reload the page, you’d get a client-side error: “The document cannot change while Printing or in Print Preview.” A quick Google led me here. Seems to be a bug in Firefox. Fine. I tried increasing the setTimeout interval to 5000, this did the trick. After some monkeying with it, 4 seconds is the ideal length of time to keep the iframe alive so that Firefox can reclaim the browser from the print process. I get the sinking feeling, however, that this will vary from client-to-client. Some people’s printers are faster or slower to spool than others (or than XPS Writer). So the solution feels a little fragile to me, but I am at the end of my JS/JQuery knowledge.

So if you happen to be a JS/JQuery expert, or you’ve done this before, drop me an email. There’s not a lot on the ‘net I could find, which leads me to believe that not a lot of people need to do this; or I am totally spacing on the obvious easy solution (like iframe.printContent()) or something.

Posted on Friday, August 14, 2009 1:33 AM | Back to top


Comments on this post: JQuery Kicked My Hiney Today

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © Lee Brandt | Powered by: GeeksWithBlogs.net