It seems that $('#someIframe').load(function(){...})
won't fire if it is attached after the iframe has finished loading. Is that correct?
What I'd really like is to have a function that is always called once when or after an iframe has loaded. To make this clearer, here are two cases:
How can I do this?
If you want to check if no page loaded inside iframe, and the iframe is not cross-domain you could check for the existence of the body tag inside of the iframe. If it exists, then something loaded. If the iframe is cross-domain, you will be blocked by the same-origin policy.
If you wish to check if there is any iframe at all, you could use getElementsByTagName('iframe'). To make live a little easier, you can take a look at jQuery. This is a Javascript library that helps you to create DOM objects and/or find them in the DOM tree.
Execute a JavaScript Function on a Load of an iFrameWe can use the onload event handler of the iframe HTML tag. The event fires once all the elements in the iframe is loaded. These include a loading of scripts, images, links, subframes etc.
You can use the iframe's load event to respond when the iframe loads. This won't tell you whether the correct content loaded: To check that, you can inspect the contentDocument. Checking the contentDocument won't work if the iframe src points to a different domain from where your code is running.
To my knowledge IFRAME's work like a normal browser, so if a page doesnt load it would be the same as if it didnt load in a normal browser window, you would get the standard page cannot be displayed message. Some questions though, what page are you going to load on client machine if it fails and how do you know it will be there?
what it does is stall out the server because the report is being created by php, but then all of a sudden the iframe is killed before it’s actually loaded. Load the script that generates the report into the top-level window instead of the IFRAME and see if it appears as expected.
The IFrameRenderer component is a basic iFrame implementation. It accepts an iFrameRef created in a parent component, this is the ref we use to check the loaded status. The load event which we will listen to is fired when the page has loaded, including all dependent resources such as stylesheets and images.
I've banged my head against a wall until I found out what's happening here.
.load()
isn't possible if the iframe has already been loaded (event will never fire).ready()
on an iframe element isn't supported (reference) and will call the callback immediately even if the iframe isn't loaded yetpostMessage
or a calling a container function on load
inside the iframe is only possible when having control over it$(window).load()
on the container would also wait for other assets to load, like images and other iframes. This is not a solution if you want to wait only for a specific iframereadyState
in Chrome for an alredy fired onload event is meaningless, as Chrome initializes every iframe with an "about:blank" empty page. The readyState
of this page may be complete
, but it's not the readyState
of the page you expect (src
attribute). The following is necessary:
.load()
eventreadyState
readyState
is complete
, we can normally assume that the iframe has already been loaded. However, because of the above-named behavior of Chrome we furthermore need to check if it's the readyState
of an empty pagereadyState
in an interval to check if the actual document (related to the src attribute) is complete
I've solved this with the following function. It has been (transpiled to ES5) successfully tested in
Function taken from jquery.mark
/** * Will wait for an iframe to be ready * for DOM manipulation. Just listening for * the load event will only work if the iframe * is not already loaded. If so, it is necessary * to observe the readyState. The issue here is * that Chrome will initialize iframes with * "about:blank" and set its readyState to complete. * So it is furthermore necessary to check if it's * the readyState of the target document property. * Errors that may occur when trying to access the iframe * (Same-Origin-Policy) will be catched and the error * function will be called. * @param {jquery} $i - The jQuery iframe element * @param {function} successFn - The callback on success. Will * receive the jQuery contents of the iframe as a parameter * @param {function} errorFn - The callback on error */ var onIframeReady = function($i, successFn, errorFn) { try { const iCon = $i.first()[0].contentWindow, bl = "about:blank", compl = "complete"; const callCallback = () => { try { const $con = $i.contents(); if($con.length === 0) { // https://git.io/vV8yU throw new Error("iframe inaccessible"); } successFn($con); } catch(e) { // accessing contents failed errorFn(); } }; const observeOnload = () => { $i.on("load.jqueryMark", () => { try { const src = $i.attr("src").trim(), href = iCon.location.href; if(href !== bl || src === bl || src === "") { $i.off("load.jqueryMark"); callCallback(); } } catch(e) { errorFn(); } }); }; if(iCon.document.readyState === compl) { const src = $i.attr("src").trim(), href = iCon.location.href; if(href === bl && src !== bl && src !== "") { observeOnload(); } else { callCallback(); } } else { observeOnload(); } } catch(e) { // accessing contentWindow failed errorFn(); } };
Consisting of two files (index.html and iframe.html): index.html:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Parent</title> </head> <body> <script src="https://code.jquery.com/jquery-1.12.2.min.js"></script> <script> $(function() { /** * Will wait for an iframe to be ready * for DOM manipulation. Just listening for * the load event will only work if the iframe * is not already loaded. If so, it is necessary * to observe the readyState. The issue here is * that Chrome will initialize iframes with * "about:blank" and set its readyState to complete. * So it is furthermore necessary to check if it's * the readyState of the target document property. * Errors that may occur when trying to access the iframe * (Same-Origin-Policy) will be catched and the error * function will be called. * @param {jquery} $i - The jQuery iframe element * @param {function} successFn - The callback on success. Will * receive the jQuery contents of the iframe as a parameter * @param {function} errorFn - The callback on error */ var onIframeReady = function($i, successFn, errorFn) { try { const iCon = $i.first()[0].contentWindow, bl = "about:blank", compl = "complete"; const callCallback = () => { try { const $con = $i.contents(); if($con.length === 0) { // https://git.io/vV8yU throw new Error("iframe inaccessible"); } successFn($con); } catch(e) { // accessing contents failed errorFn(); } }; const observeOnload = () => { $i.on("load.jqueryMark", () => { try { const src = $i.attr("src").trim(), href = iCon.location.href; if(href !== bl || src === bl || src === "") { $i.off("load.jqueryMark"); callCallback(); } } catch(e) { errorFn(); } }); }; if(iCon.document.readyState === compl) { const src = $i.attr("src").trim(), href = iCon.location.href; if(href === bl && src !== bl && src !== "") { observeOnload(); } else { callCallback(); } } else { observeOnload(); } } catch(e) { // accessing contentWindow failed errorFn(); } }; var $iframe = $("iframe"); onIframeReady($iframe, function($contents) { console.log("Ready to got"); console.log($contents.find("*")); }, function() { console.log("Can not access iframe"); }); }); </script> <iframe src="iframe.html"></iframe> </body> </html>
iframe.html:
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Child</title> </head> <body> <p>Lorem ipsum</p> </body> </html>
You can also change the src
attribute inside index.html
to e.g. "http://example.com/". Just play around with it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With