iframe behaviour of onload vs addEventListener('load')

52,852

Solution 1

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>

Solution 2

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.

Share:
52,852
roryf
Author by

roryf

Every time you link to w3schools, a kitten dies.

Updated on May 24, 2020

Comments

  • roryf
    roryf almost 4 years

    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?

  • roryf
    roryf about 13 years
    Can't use ready event since this requires a document that doesn't exist yet, unless I'm missing something.
  • Jamie Treworgy
    Jamie Treworgy about 13 years
    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-plug‌​in 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.
  • roryf
    roryf about 13 years
    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.
  • Jamie Treworgy
    Jamie Treworgy about 13 years
    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/…
  • roryf
    roryf about 13 years
    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 :(
  • Jamie Treworgy
    Jamie Treworgy about 13 years
    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-ifra‌​mes ... it doesn't seem like there's any really clean way to do this.
  • roryf
    roryf about 13 years
    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!
  • roryf
    roryf almost 13 years
    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.