0

I am trying to first create an iframe and then inject into it jQuery library and then have an alert to say that jQuery has loaded.

The jQuery library is being inserted into the iframe head as expected and the alert on jQuery load into the body.

The problem is, it does not show the alert and instead says jQuery is not defined.

Can anyone suggest anything?

Here is the code

<!doctype html>
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
        <title>iFrame Test</title>
    </head>
    <body>
        <script>
            var insertScript = function(src){
                var script = document.createElement('script');
                script.type = 'text/javascript';
                script.async = false;
                script.src = src;
                $('iframe').contents().find('head')[0].appendChild(script);
            }

            var insertScriptContent = function(code){
                var script = document.createElement('script');
                script.type = 'text/javascript';
                script.async = false;
                script.innerHTML  = code;
                $('iframe').contents().find('body')[0].appendChild(script);
            }

            $(function(){
                $('iframe').load(function(){
                    var contents = $('iframe').contents();
                    insertScript('https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js');
                    insertScriptContent('jQuery(function(){ alert("loaded"); });');
                });
            });
        </script>

        <div class="output">
            <iframe></iframe>
        </div>
    </body>
</html>
arulmr
  • 8,620
  • 9
  • 54
  • 69
Dan
  • 1,295
  • 2
  • 22
  • 46
  • Not a straight answer, but should help you figure out what you need: [Accessing iframe content](http://stackoverflow.com/questions/364952/jquery-javascript-accessing-contents-of-an-iframe). Keep in mind, this will not work if the iframe is loaded with content from another domain. – Vimal Stan Apr 17 '13 at 05:46
  • 1
    i meant to say its same domain and actually same page – Dan Apr 17 '13 at 05:48

1 Answers1

2

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.

Michael Geary
  • 28,450
  • 9
  • 65
  • 75
  • the annoying thing is that it doesnt work on my iphone... because the iframe has no src it never completes the load! – Dan Apr 17 '13 at 08:23