1
votes

I have the following code that works on Chrome and MS Edge but not on Firefox.

Parent.html has this script.

<html>
<body>
<script>
var ifr1 = document.createElement('iframe');

ifr1.onload = function() {
    alert("iframe 1 loaded") //fires on all browsers
    script = ifr1.contentWindow.document.createElement('script');
    script.src = 'PATH/TO/script.js';
    script.onload = function() {
        alert("script 1 onload") //fires on all browsers
    };
    ifr1.contentWindow.document.body.appendChild(script);
};
document.body.appendChild(ifr1);

</script>
</body>
</html>

It creates an iframe and loads script.js within that iframe.

Here is script.js which does the same thing like above -

var ifr2 = document.createElement('iframe');

ifr2.onload = function() {
    alert("iframe 2 loaded") //doesn't fire on Firefox
    script = ifr2.contentWindow.document.createElement('script');
    script.src = 'https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js';
    script.onload = function() {
        alert("script 2 onload")
    };
    ifr2.contentWindow.document.body.appendChild(script);
};
document.body.appendChild(ifr2);

It creates another iframe ifr2 within the iframe ifr1 created by Parent.html.

Now, Chrome and Edge show all the alerts properly but Firefox doesn't fire the onload event for ifr2 loaded within ifr1 (even IE fires the onload for ifr2). Any idea why?

3
Any messages on the devtools console? - Jaromanda X

3 Answers

1
votes

A workaround is to create a simple html page - even just <html><head></head><body></body></html> (maybe even less) .. lets call it empty.html

if you now change Parent.html to

<html>
<body>
<script>
var ifr1 = document.createElement('iframe');

ifr1.onload = function() {
    alert("iframe 1 loaded") //fires on all browsers
    script = ifr1.contentWindow.document.createElement('script');
    script.src = 'PATH/TO/script.js';
    script.onload = function() {
        alert("script 1 onload") //fires on all browsers
    };
    ifr1.contentWindow.document.body.appendChild(script);
};
ifr1.src = 'empty.html'; // add this code *******
document.body.appendChild(ifr1);

</script>
</body>
</html>

Then it works as expected

Not sure why firefox does what it does - it could be because without the src attribute, the iframe's location is about:blank - but why the first one works and not the second is a mystery to me

edit: well, it did once then stopped again!!

OK, really strange - if you add ifr1.src = 'empty.html' it works ... if you duplicate that in script.js it breaks again

Not sure I've answered you well, but at least I've given you a working kludge :p

0
votes

IMO this is a bug in Firefox because Firefox doesn't execute the load event inside iframes the way you would expect. The developers over at Mozilla may disagree. It all comes down to your definition of what "load" should mean, and it's more complicated than you think.

In any case the real issue is when to know it's safe to access ifr2.contentWindow, and the whole point of using ifr2.onload the way you did is so that you can figure out when ifr2.contentWindow exists.

Note, however, that the contentWindow and document are created immediately when document.body.appendChild(ifr2) executes, so if you move the appendChild() call to above your current code and remove the onload function, it will work as expected.

Alternatively you can change the onload function to something else and execute it directly after appendChild(), as such:

var ifr2 = document.createElement('iframe');
function loadit() {
    console.log("iframe 2 loaded")
    script = ifr2.contentWindow.document.createElement('script');
    script.src = '...';
    script.onload = function() {
        console.log("script 2 onload")
    };
    ifr2.contentWindow.document.body.appendChild(script);
};

// add the iframe to the document
document.body.appendChild(ifr2);

// now execute your script stuff:
loadit()

This should work across all (modern) browsers.

0
votes

While this is a bad practice and deprecated in chrome (it will show a warning in console. adding this line before apending script tag fix the issue for me:

iframe.contentWindow.document.write('<html><head></head><body></body></html>');

It appears firefox needs it to init iframe and run javascript...