Detecting when Iframe content has loaded (Cross browser)

195,407

Solution 1

to detect when the iframe has loaded and its document is ready?

It's ideal if you can get the iframe to tell you itself from a script inside the frame. For example it could call a parent function directly to tell it it's ready. Care is always required with cross-frame code execution as things can happen in an order you don't expect. Another alternative is to set ‘var isready= true;’ in its own scope, and have the parent script sniff for ‘contentWindow.isready’ (and add the onload handler if not).

If for some reason it's not practical to have the iframe document co-operate, you've got the traditional load-race problem, namely that even if the elements are right next to each other:

<img id="x" ... />
<script type="text/javascript">
    document.getElementById('x').onload= function() {
        ...
    };
</script>

there is no guarantee that the item won't already have loaded by the time the script executes.

The ways out of load-races are:

  1. on IE, you can use the ‘readyState’ property to see if something's already loaded;

  2. if having the item available only with JavaScript enabled is acceptable, you can create it dynamically, setting the ‘onload’ event function before setting source and appending to the page. In this case it cannot be loaded before the callback is set;

  3. the old-school way of including it in the markup:

    <img onload="callback(this)" ... />

Inline ‘onsomething’ handlers in HTML are almost always the wrong thing and to be avoided, but in this case sometimes it's the least bad option.

Solution 2

See this blog post. It uses jQuery, but it should help you even if you are not using it.

Basically you add this to your document.ready()

$('iframe').load(function() {
    RunAfterIFrameLoaded();
});

Solution 3

For those using React, detecting a same-origin iframe load event is as simple as setting onLoad event listener on iframe element.

<iframe src={'path-to-iframe-source'} onLoad={this.loadListener} frameBorder={0} />

Solution 4

For anyone using Ember, this should work as expected:

<iframe onLoad={{action 'actionName'}}  frameborder='0' src={{iframeSrc}} />

Solution 5

  1. This code detects when iframe content has loaded Without jquery:

Credit Biranchi's answer

    // wait for the doc to load (wait for the class 'iframe...' to load) before sending the script
    checkIframeLoaded()
    
    function checkIframeLoaded() {
        // console.log(" function checked")
        // Get a handle to the iframe element
        var iframe = document.getElementsByClassName("docs-texteventtarget-iframe")[0];
        console.log("iframe", iframe)
        // check if the iframe is loaded or not (= undefined = null)
        if (iframe == null) {
            // If we are here, it is not loaded. Set things up so we check the status again in 1000 milliseconds
            window.setTimeout(checkIframeLoaded, 1000);
        } else {
            var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
            // Check if loading is completed
            if (iframeDoc.readyState == 'complete') {
    
                // The loading is complete, call the function we want executed once the iframe is loaded
                iframeDoc.addEventListener("keydown", dispatchkeyboard, false);
            } else {
                // even if the iframe is loaded the "readystate may not be completed yet" so we need to recall the function.
                window.setTimeout(checkIframeLoaded, 1000);
            }
        }
    }
    
  
  1. This code works with jquery:

Credit: gilles bousquet's answer

    // use jquery to detect when iframe is loaded but doesn't work offline
    // (this code needs jQuery because it use the "$" below). if you use it; add this require in the ===usercript=== section
    //  @require    http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js

    var editingIFrame = $('iframe.docs-texteventtarget-iframe')[0];
   if (editingIFrame) {
        console.log("inside doc.getele")
        editingIFrame.contentDocument.addEventListener("keydown", dispatchkeyboard, false);
    }
    
Share:
195,407
David Snabel-Caunt
Author by

David Snabel-Caunt

Software Engineer at Twitter. I've been programming professionally for about 13 years and I specialise in iOS – Objective-C &amp; Swift. You can check out my CV here.

Updated on July 08, 2022

Comments

  • David Snabel-Caunt
    David Snabel-Caunt almost 2 years

    I'm trying to detect when an iframe and its content have loaded but not having much luck. My application takes some input in text fields in the parent window and updates the iframe to provide a 'live preview'

    I started with the following code (YUI) to detect when the iframe load event occurs.

    $E.on('preview-pane', 'load', function(){
        previewBody = $('preview-pane').contentWindow.document.getElementsByTagName('body')[0];
    }
    

    'preview-pane' is the ID of my iframe and I'm using YUI to attach the event handler. However, trying to access the body in my callback (upon iframe load) fails, I think because the iframe loads before the event handler is ready. This code works if I delay the iframe loading by making the php script that generates it sleep.

    Basically, I'm asking what is the correct approach across browsers to detect when the iframe has loaded and its document is ready?

  • David Snabel-Caunt
    David Snabel-Caunt about 15 years
    Interesting, but the problem I have is with the load events and timing. I am listening for the load event as advised by that article.
  • David Snabel-Caunt
    David Snabel-Caunt about 15 years
    Thanks. My solution checks the readyState (if exists), then the body elements innerHTML length to see if it has loaded. If not, attaches the load event handler. Seems to work ok
  • Christian
    Christian about 13 years
    -1 - inline events are not "bad", that's just the current fad. In fact, inline events are easier to debug and understand, unlike their magic counterparts (which, on the other hand, are easier to attach, stack and use seamlessly).
  • haknick
    haknick almost 13 years
    @Christian, inline events are also the best option when you need to attach an event to every element of a very long list. Since you're already looping to build the list on the server side, it's much more efficient to attach the inline-event as well.
  • David Snabel-Caunt
    David Snabel-Caunt over 12 years
    @haknick Wouldn't you want to use a single event listener on the list, and use an event delegate? This would be more efficient.
  • simo
    simo almost 12 years
    This solution works: stackoverflow.com/a/11874986/1260020 If you want to use clean javascript go for the interval solution and inside the interval access iframe's content using one of the methods mentioned in the same thread.
  • Sudheer Someshwara
    Sudheer Someshwara almost 11 years
    This would not work if the iframe is cross-domain. The script inside iframe cannot access parent window.
  • shorif2000
    shorif2000 over 9 years
    i have tried this with console.log. it gets logged after the iframe has loaded.
  • L_K
    L_K almost 6 years
    Can onLoad event can only trigger for same-origin iframe?