You're loading jQuery asynchronously (despite the script.async=false
) and then loading your alert script immediately after that. jQuery is not yet loaded when that script runs, so you get the undefined jQuery
reference.
As a quick fix, I added a setInterval()
that waits until jQuery
is defined. I also made these other changes:
- Removed the
script.async = false;
both places because it doesn't do any good.
- Removed the
$('iframe').load()
wrapper. When I tested your code, the callback function in that wrapper never gets called at all. That's not surprising since nothing is being loaded into the iframe at that point.
- Changed the two places where you use
document.createElement()
to use the iframe document (called iframedoc
in my version) instead. It works OK using document
, but I'm a bit more comfortable creating those scripts under the document they will be loaded into.
- Changed two instances of
...find(something)[0].appendChild();
to the simpler ...find(something).append();
.
Here's the working code:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript">
</script>
<title>iFrame Test</title>
</head>
<body>
<script type="text/javascript">
$(function() {
var $contents = $('iframe').contents();
var iframedoc = $contents[0];
var insertScript = function(src) {
var script = iframedoc.createElement('script');
script.type = 'text/javascript';
script.src = src;
$('iframe').contents().find('head').append(script);
}
var insertScriptContent = function(code) {
var script = iframedoc.createElement('script');
script.type = 'text/javascript';
script.innerHTML = code;
$('iframe').contents().find('body').append(script);
}
insertScript('https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js');
insertScriptContent(
'var timer = setInterval( function() {' +
'if( typeof jQuery == "undefined" ) return;' +
'clearInterval( timer );' +
'jQuery(function(){ alert("loaded"); });' +
'}, 50 )'
);
});
</script>
<div class="output">
<iframe></iframe>
</div>
</body>
</html>
That was good for a first pass, but there's a simpler way to do it. I tried replacing the two script functions with jQuery code, so here is another working version:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript">
</script>
<title>iFrame Test</title>
</head>
<body>
<script type="text/javascript">
$(function() {
var $contents = $('iframe').contents();
$contents.find('head').append(
'<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"><\/script>'
);
$contents.find('body').append(
'<script>' +
'jQuery(function(){ alert("loaded"); });' +
'<\/script>'
);
});
</script>
<div class="output">
<iframe></iframe>
</div>
</body>
</html>
Oddly enough, this one works OK without the setInterval()
timer, so I took that code out. I'm not sure exactly why this works - which is not a comforting feeling - but it does seem to be consistent in the browsers I tested it in.
And finally, here is a non-working experiment. In the past I've used document.write()
targeting an iframe to good effect. So I thought I would try that:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript">
</script>
<title>iFrame Test</title>
</head>
<body>
<script type="text/javascript">
$(function() {
var $contents = $('iframe').contents();
var iframedoc = $contents[0];
iframedoc.write(
'<!doctype html>',
'<html>',
'<head>',
'<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.js"><\/script>',
'</head>',
'<body>',
'<script>',
'debugger;',
'jQuery( function(){ alert("loaded"); } );',
'<\/script>',
'</body>',
'</html>'
);
});
</script>
<div class="output">
<iframe></iframe>
</div>
</body>
</html>
This version does load jQuery and the inline script into the iframe, and it executes the jQuery()
call in the inline script. But it never calls the callback function with the alert()
in it. This actually relates to something I'm working on, so I'll probably take another look at it tomorrow, but in the meantime I left the experimental code in case you're curious. I changed it to use the uncompressed jQuery inside the iframe for easy debugging, and left a debugger;
statement in there.