iframe behaviour of onload vs addEventListener('load')
Asked Answered
P

3

21

I've been playing around with adding hidden iframe elements to a page, and I want to manipulate the DOM of the these once loaded. I've noticed that I can't start manipulating the DOM immediately after adding the iframe to a page since it hasn't loaded yet. This can't be done with the DOMContentLoaded event since that fires against the document which doesn't exist in the iframe until it is added to the page, so we have to use the load event.

Here is some test code:

var iframe = document.createElement('iframe');
iframe.onload = function() { console.log('loaded!'); };
document.getElementsByTagName('body')[0].appendChild(iframe);

This works as expected, however when I change it to addEventListener it doesn't even get added to the DOM:

var iframe = document.createElement('iframe');
iframe.addEventListener('load', function() { console.log('loaded!'); });
document.getElementsByTagName('body')[0].appendChild(iframe);

I haven't tested attachEvent in IE.

Anyone shed any light on this?

Pugh answered 7/3, 2011 at 14:26 Comment(0)
V
23

addEventListener() function needs 3 arguments! Take a look at https://developer.mozilla.org/en/DOM/element.addEventListener

The 3rd argument is marked as optional, but then they write:

Note that this parameter is not optional in all browser versions.

I'm not sure when and where it is required, but my tests on FF4 threw an exception when calling the addEventListener with 2 arguments:

uncaught exception: [Exception... "Not enough arguments" nsresult: "0x80570001 (NS_ERROR_XPC_NOT_ENOUGH_ARGS)" location: "JS frame :: http://localhost/index.php :: :: line 10" data: no]

By the way, your code works well in Chrome [the string loaded! is logged in console].

Like FF, IE9 needs the 3rd argument in the standards mode (with <!DOCTYPE html>). IE9 is the first IE that supports W3C's event model. So in the earlier versions we need to try attachEvent. I don't have earlier IEs, but it worked in IE7/8 Standards Mode and even in Quirks Mode in IE9. Here is the code I used:

<!DOCTYPE html>
<html>
<head><title></title></head>
<body>
<script>
    window.onload=function(){
        var iframe = document.createElement('iframe');
        var func = function() { console.log('loaded!');};
        if(iframe.addEventListener)
            iframe.addEventListener('load', func, true);
        else if(iframe.attachEvent)
            iframe.attachEvent('onload',func);
        document.body.appendChild(iframe);
    }
</script>
</body>
</html>
Vincentia answered 23/5, 2011 at 17:14 Comment(1)
I believe your point about the 3rd parameter was exactly the problem, I wasn't getting the error you did but it was probably just being suppressed somehow. I can't recall but clearly I didn't test it in Chrome (silly me...). Nice one, thanks.Pugh
C
1

This is working for me:

html:

iframe source code: <br />
<textarea id="output" rows="20" cols="60">loading ...</textarea>

javascript (on documentReady):

var iframe = document.createElement('iframe');
iframe.id = iframe.name = "testframe";
iframe.src = "http://fiddle.jshell.net";
iframe.width = 400;
iframe.height = 100;
iframe.style.display = "none";

if (iframe.addEventListener)
    iframe.addEventListener("load", loaded, false);
else
    iframe.attachEvent("onload", loaded);

function loaded() {
    var html;
    if (iframe.contentDocument)
        html = iframe.contentDocument.getElementsByTagName("HTML")[0].innerHTML;
    else
        html = window.frames[iframe.name].document.getElementsByTagName("html")[0].innerHTML;

    document.getElementById("output").value = html;
}

document.getElementsByTagName("body")[0].appendChild(iframe);

See the Demo at: http://jsfiddle.net/WcKEz/

Works with addEventListener, but includes the fallback to attachEvent. Access to the DOM of the IFRAME of course only on the same domain.

Coverley answered 23/5, 2011 at 16:5 Comment(0)
P
0

Does the first example work? Not sure exactly what you're looking for, but this should illuminate when events work: jQuery document.ready source

$(document).ready equivalent without jQuery

addEventListener does not work in IE, so if that's where you're testing, then the 2nd would fail before the iframe gets appended.

You could also add a callback from the page itself, though (for example, using jQuery so you don't reinvent the wheel) I suspect $(iframe).ready() {..} would give you consistent behavior.

Petulancy answered 7/3, 2011 at 15:29 Comment(7)
Can't use ready event since this requires a document that doesn't exist yet, unless I'm missing something.Pugh
I'm suggesting using the same logic as jquery document.ready on the iframe element, e.g. like this plugin seems to do: thunderguy.com/semicolon/2007/08/14/elementready-jquery-plugin but still not clear if there's something wrong with your first code snippet, are you trying to hook before images are loaded? Alternatively, assuming you control the code in the iframe, you could use document.ready there to callback to a function using parent.Petulancy
The first code snippet works correctly (as was stated), however the onload property is non-standard (AFAIK) and I just wondered why the standards-compliant way (ignoring IE) wasn't working. The iframe itself does not point to another page, I want to load it up blank and populate the DOM.Pugh
onload seems to be ok: w3schools.com/jsref/event_frame_onload.asp i kind of missed you were building this whole thing dynamically. Take a look at this... old but maybe will help. bytes.com/topic/javascript/answers/…Petulancy
Frankly I would put more credit by my morning crap than w3schools (too far? yeah, too far...). But, the other link looks interesting - the person resorted to using document.write which I have a suspicion I may have come across having to use on a project some years ago. Now if only I had the code lying around :(Pugh
Haha! Well fair enough.. though I thought his technique looked reasonable (as a way of testing the different ways of accessing the doc). Here's a more detailed blog post along the same lines written by someone who appears to be out of junior high school: thomas.bindzus.me/2007/12/24/adding-dynamic-contents-to-iframes ... it doesn't seem like there's any really clean way to do this.Petulancy
Another interesting link. Doesn't answer my original question of why one event handler works vs the other, but could provide a work-around that negates the need for an event handler at all. Thanks!Pugh

© 2022 - 2024 — McMap. All rights reserved.