Friday, March 4, 2011

Javascript callback when IFRAME is finished loading?

I need to execute a callback when an IFRAME has finished loading. I have no control over the content in the IFRAME, so I can't fire the callback from there.

This IFRAME is programmaticly created, and I need to pass its data as a variable in the callback, as well as destroy the iframe.

Any ideas?

EDIT:

Here is what I have now:

function xssRequest(url, callback)
{
    var iFrameObj = document.createElement('IFRAME');
    iFrameObj.src = url;   
    document.body.appendChild(iFrameObj); 

    $(iFrameObj).load(function() 
    {
     document.body.removeChild(iFrameObj);
     callback(iFrameObj.innerHTML);
    });
}

This callsback before the iFrame has loaded, so the callback has no data returned.

From stackoverflow
  • Try this:

    iframe.contentWindow.onload = yourcallbackfunction;

    Should work in IE at least.

    FlySwat : That doesn't appear to work in FF or IE.
  • I've had exactly the same problem in the past and the only way I found to fix it was to add the callback into the iframe page. Of course that only works when you have control over the iframe content.

    roryf : I fail to see what was wrong with this suggestion and why it was voted down. Some people eh....
    Elmo Gallen : I didn't vote you down, but I imagine you got voted down because you suggested exactly what he said he can't do -- he did say specifically, "I have no control over the content in the IFRAME, so I can't fire the callback from there."
  • Can you try switching the order of:

        document.body.removeChild(iFrameObj);
        callback(iFrameObj.innerHTML);
    
    FlySwat : No difference, only I get blank content, then it removes it.
  • You can use observe() method of HTMLElement to set the 'load' handler:

    iFrameObj.observe('load', function(e) {....});
    

    Also, I'd suggest to set an inner spanning DIV inside the iframe and set load handler to it.

  • I have a similar code in my projects that works fine. Adapting my code to your function, a solution could be the following:

    function xssRequest(url, callback)
    {
        var iFrameObj = document.createElement('IFRAME');
        iFrameObj.id = 'myUniqueID';
        document.body.appendChild(iFrameObj);       
        iFrameObj.src = url;                        
    
        $(iFrameObj).load(function() 
        {
            callback(window['myUniqueID'].document.body.innerHTML);
            document.body.removeChild(iFrameObj);
        });
    }
    

    Maybe you have an empty innerHTML because (one or both causes): 1. you should use it against the body element 2. you have removed the iframe from the your page DOM

  • First up, going by the function name xssRequest it sounds like you're trying cross site request - which if that's right, you're not going to be able to read the contents of the iframe.

    On the other hand, if the iframe's URL is on your domain you can access the body, but I've found that if I use a timeout to remove the iframe the callback works fine:

    // possibly excessive use of jQuery - but I've got a live working example in production
    $('#myUniqueID').load(function () {
      if (typeof callback == 'function') {
        callback($('body', this.contentWindow.document).html());
      }
      setTimeout(function () {$('#frameId').remove();}, 50);
    });
    
    Sam Soffes : you could replace `$('body', this.contentWindow.document).html()` with `this.contentDocument.body.outerHTML`
  • I have had to do this in cases where documents such as word docs and pdfs were being streamed to the iframe and found a solution that works pretty well. The key is handling the onreadystatechanged event on the iframe.

    Lets say the name of your frame is "myIframe". First somewhere in your code startup (I do it inline any where after the iframe) add something like this to register the event handler:

    document.getElementById('myIframe').onreadystatechange = MyIframeReadyStateChanged;
    

    I was not able to use an onreadystatechage attribute on the iframe, I can't remember why, but the app had to work in IE 7 and Safari 3, so that may of been a factor.

    Here is an example of a how to get the complete state:

    function MyIframeReadyStateChanged()
    {
        if(document.getElementById('myIframe').readyState == 'complete')
        {
            // Do your complete stuff here.
        }
    }
    
  • I think the load event is right. What is not right is the way you use to retreive the content from iframe content dom.

    What you need is the html of the page loaded in the iframe not the html of the iframe object.

    What you have to do is to access the content document with iFrameObj.contentDocument. This returns the dom of the page loaded inside the iframe, if it is on the same domain of the current page.

    I would retreive the content before removing the iframe.

    I've tested in firefox and opera.

    Then i think you can retreive your data with $(childDom).html() or $(childDom).find('some selector') ...

  • The innerHTML of your iframe is blank because your iframe tag doesn't surround any content in the parent document. In order to get the content from the page referred to by the iframe's src attribute, you need to access the iframe's contentDocument property. An exception will be thrown if the src is from a different domain though. This is a security feature that prevents you from executing arbitrary JavaScript on someone else's page, which would create a cross-site scripting vulnerability. Here is some example code the illustrates what I'm talking about:

    <script src="http://prototypejs.org/assets/2009/8/31/prototype.js"
            type="text/javascript"></script>
    
    <h1>Parent</h1>
    
    <script type="text/javascript">
    function on_load(iframe) {
      try {
        // Displays the first 50 chars in the innerHTML of the
        // body of the page that the iframe is showing.
        alert(iframe.contentDocument.body.innerHTML.substring(0, 50));
      } catch (e) {
        // This can happen if the src of the iframe is
        // on another domain
        alert('exception: ' + e);
      }
    }
    </script>
    <iframe id="child"
            src="iframe_content.html"
            onload="on_load(this)"></iframe>
    

    To further the example, try using this as the content of the iframe:

    <h1>Child</h1>
    
    <a href="http://www.google.com/">Google</a>
    
    Use the preceeding link to change the src of the iframe
    to see what happens when the src domain is different from
    that of the parent page
    

0 comments:

Post a Comment