I created an iframe dynamically and found that this iframe trigger onload event twice.
var i=0;
frameOnload=function(){
console.log(i++);
};
var ifr=doc
Building on @jakub.g's answer:
From inside the frame, the evt.target.src
hack does not work. But I found that I could instead check the evt.target.title
. The second time DOMContentLoaded
is triggered, evt.target
points to the document being loaded, so this would work:
document.addEventListener('DOMContentLoaded', function(evt) {
if (evt.target.title !== myPageTitle) {
// Work around for Webkit browsers trigging this event twice om iframes
return
}
// DOM content loaded, for real
}
This behavior seems to be consistent even in Internet Explorer (save for old versions without .addEventListener
Here code that works good!
Credit: @Dave Stolie https://coderanch.com/t/443223/languages/Frames-loading-refresh
<html>
<head>
<script type="text/javascript">
function loadFrame()
{
var url="http://www.google.com";
alert(document.getElementById("theFrame").src);
if (document.getElementById("theFrame").src != url)
{
alert("loading");
document.getElementById("theFrame").src = url;
}
}
</script>
</head>
<body onLoad="loadFrame();">
<iframe id="theFrame" src="x"/>
</body>
</html>
FWIW, while I was able to reproduce double onload
in case where iframe.src
is javascript:
, I was not able to reproduce it with a normal HTTP URL (onload was happening once). However, when you change the order of calls so that iframe.src
is set after appending to body, then the double-load happens (again, webkit only):
var i = 0;
var iframe = document.createElement("iframe");
iframe.onload = function(){
console.log("frameOnload", ++i);
};
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/";
//iframe.src = "http://www.example.org/404";
// double onload!
When I assign src
before appending, I get one onload
call.
var i = 0;
var iframe = document.createElement("iframe");
iframe.onload = function(){
console.log("frameOnload", ++i);
};
iframe.src = "http://www.example.org/";
//iframe.src = "http://www.example.org/404";
document.body.appendChild(iframe);
// only one onload
I've had this happen to asynchronously loaded stylesheets, like this one.
<link rel="preload" href="stylesheet.css" as="style" onload="this.rel='stylesheet'">
I find that the simplest solution is to have the event remove itself:
<link rel="preload" href="stylesheet.css" as="style" onload="this.removeAttribute('onload'); this.rel='stylesheet'">
To expand on the top-voted answer: if you can not control when and how things are attached to the DOM -- for instance, when using a framework (we've had this happening in our Angular app) -- you might want to try the solution below.
I did heavy cross-browser testing and I found the following workaround: check the parameter passed to onload
callback and inspect evt.target.src
in the event listener.
iframe.onload = function(evt) {
if (evt.target.src != '') {
// do stuff
}
}
(if you call global method from HTML, remember to pass event
in your HTML markup: <iframe onload="window.globalOnLoad(event)">
)
evt.target.src
can be be ''
(empty string) only in webkit in the first onload
call, from my tests.
iframe.onload = function(evt){
console.log("frameOnload", ++i);
console.log("src = '" + evt.target.src + "'");
};
// Chrome: onload 1 src='', onload 2 src=requestedSrc
// IE11: onload 1 src=requestedSrc
// Firefox: onload 1 src=requestedSrc
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/";
// Chrome: onload 1 src='', onload 2 src=requestedSrc
// IE11: onload 1 src=requestedSrc
// Firefox: onload 1 src=requestedSrc
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/404";
// Chrome: onload 1 src='', onload 2 src=requestedSrc
// IE11: onload 1 src=requestedSrc
// Firefox: onload NEVER triggered!
document.body.appendChild(iframe);
iframe.src= 'http://aaaaaaaaaaaaaaaaaaaaaa.example/';
iframe.src
explicitly set to about:blank
before appending to DOM// Chrome: onload 1 src='about:blank', onload 2 src=requestedSrc
// IE11: onload 1 src=requestedSrc
// Firefox: onload 1 src=requestedSrc
iframe.src = "about:blank";
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/";
iframe.src
explicitly set to a javascript expression before appending to DOM// Chrome: onload 1 src='javascript:void 0', onload 2 src=requestedSrc
// IE11: onload 1 src=requestedSrc
// Firefox: onload 1 src=requestedSrc
iframe.src = "javascript:void 0";
document.body.appendChild(iframe);
iframe.src = "http://www.example.org/";
I've also encountered the same problem, but get no answer anywhere, so I tested by myself.
The iframe onload event will be triggered twice in webkit browsers ( safari/chrome ), if you attach the onload event BEFORE the iframe is appended to the body.
So you can prevent iframe onload twice by change your codes in the following way.
document.body.appendChild(ifr);
ifr.onload=frameOnload; // attach onload event after the iframe is added to the body
Then, you will only get one onload event, which is the event the document really loaded.