I have basically the opposite problem to this question: How to prevent iframe from loading when injected into the DOM?
I wish to load an IFRAME
element which is not injected into the DOM.
I am attempting to print a page via javascript. The goal is to avoid having to navigate a link, issue a print command, and navigate back.
I have jQuery available to me.
// fake table that illustrates pertanent DOM
<table class=diary><tr><td data-job=12345 contextmenu=job_menu><a href=/jobs/12345>view job 12345</a></table>
// real code
<menu type="context" id="job_menu">
<menuitem label="Print Job" onclick="PrintJob(); return false;"></menuitem>
</menu>
<script type="text/javascript">
var target = null;
function PrintJob()
{
var job_no = $(target).data('job');
if(job_no > 0) {
$('<iframe name="printjob" src="/jobs/'+job_no+'">').load(function () {
this.focus();
this.print();
})
.trigger('load');
}
}
$('.diary').bind('contextmenu', function (ev) {
var td = ev.target;
while(td && td.nodeName != 'TD')
td = td.parentNode;
target = td;
});
</script>
The problem is that calling .trigger('load')
on the generated IFRAME
element does not cause a GET
request on the src
attribute URL. I was hoping the default handler would be called first, then my attached handler would fire, and print the contents of the iframe, but my load handler just gets called immediatly.
I can't attach the print call to the iframe's contentDocument.onready
event because contentDocument
is nil until the frame has loaded. I don't know if you can focus an element not in the DOM or if that is necessary for printing, but the code I have seen elsewhere all had .focus()
preceeding .print()
(I also tried using window.frames['printjob'].print()
, but I suspect window.frames['printjob']
is nil if the iframe is not yet in the window :)
As Tom van der Woerdt said, the iframe
won't load unless you add it to the DOM.
But that doesn't mean it has to be visible:¹
$(`<iframe name="printjob" src="/jobs/'+job_no+'" style="display: none">`)
.load(function() {
this.contentWindow.focus();
this.contentWindow.print();
})
.appendTo(document.body);
Note the display: none
. In my experiments with modern browsers (and those of user2027290, who pointed this out), the iframe
gets loaded, and the print dialog shown.
The trick is figuring out when to remove it. Modern browsers have an afterprint
event you could use. Or you could just remove it prior to the next time the user prints, avoiding having more than one of them.
¹ In the 2011 version of this answer, I had it loaded visibly but outside the viewport, like this:
$('<iframe name="printjob" src="/jobs/'+job_no+'" style="position: absolute; left: -10000px; top: 0">')
.load(function() {
this.contentWindow.focus();
this.contentWindow.print();
})
.appendTo(document.body);
I don't recall whether I did that because display: none
didn't work at the time or because I just didn't think of it, but if you run into any issue with the display: none
solution, that might be a fallback to try.