3

Here is a snippet of code that uses a script to populate the contents of an iframe:

<!doctype html>
<html>
    <head>
        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
        <script>
        $(document).ready(function() {
            $('iframe').contents().find('body').html('<script>console.log($("div"))<\/script>');
        });
        </script>
    </head>
    <body>
        <div>Test</div>
        <iframe />
    </body>
</html>

When executed we see that the iframe has access to the parent's DOM and we see the div being selected by the jQuery selector. The iframe does not have jQuery included but it can access the jQuery object of the parent.

However if we write the same thing via an iframe src inclusion, the behavior is different:

test.html:

<!doctype html>
<html>
    <head>
        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    </head>
    <body>
        <div>Test</div>
        <iframe src="another.html">
    </body>
</html>

another.html:

<!doctype html>
<html>
    <head>
        <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
        <script>
        $(document).ready(function() {
            console.log($('div'));
        });
        </script>
    </head>
    <body>

    </body>
</html>

We now see that the page does not list any divs. Further, if we don't include the jQuery js in the child page, it would throw an error.

Note that both pages are in the same domain, so we don't have same-origin policy issues.

My questions are:

  1. Why is the behavior different for the 2 - a. manipulating the iframe DOM from the parent and b. including the iframe content via a src?
  2. Is there a way to make the parent have access to the child and NOT vice-versa?
buzypi
  • 1,522
  • 1
  • 12
  • 15
  • Can you please clarify your test case. What are you testing? The test cases don't see to be equal. – Halcyon Oct 04 '13 at 15:28
  • Let me clarify - in one I generate the HTML within the iframe programmatically via jQuery and in the other I do it by including a src that contains the code. I will make it similar if you want but if I do the second will throw an error. If you see the output of the 2, the first one returns the div of the parent page, while the second one doesn't. – buzypi Oct 04 '13 at 15:31

1 Answers1

1

So the first bit of code gives 1 and the second bit of code gives 0?

That seems correct.

In the first example $ is bound to the parent frame. In the second example, since you have a new instance of jQuery it's bound to the iframe.


In:

$(document).ready(function() {
    $('iframe').contents().find('body').html('<script>console.log($("div"))<\/script>');
});

jQuery's html function will do an eval on the script-part of the inserted HTML. That eval will run in the scope of the parent so it uses the parent instance of $.

If you just moved the script to the iframe it will fail because it doesn't have access to $.

Halcyon
  • 57,230
  • 10
  • 89
  • 128
  • While that might seem to be the reason, I am not sure about it. The reason is, if I remove the line: `` from another.html wouldn't you expect it to use the parent's jQuery object? You will see that it doesn't happen. – buzypi Oct 04 '13 at 15:38
  • No of course not because `$` is not defined in the iframe. But since you're using jQuery's `html` there is actually an `eval` on the script part which gives you access to the parent's `$`. – Halcyon Oct 04 '13 at 15:39
  • 1
    Ok that seems to make sense! Can you tell me if there is a way to embed HTML in the iframe without the parent evaluating it but the child evaluating it? – buzypi Oct 04 '13 at 15:43
  • Sure: don't use jQuery's `html` function. If you don't have the magic `eval` you wont run into this weird scoping issue. – Halcyon Oct 04 '13 at 15:46