5

Because of the widget format I'm working with I have a page which has multiple iframes embedded within iframes. I won't paste the code as it's vast and unwieldy but it is essentially just this:

<html>
    <head></head>
    <body>
        <iframe>
            <html>
                <head></head>
                <body>
                    <iframe>
                        <html>
                            <head></head>
                            <body>
                                <iframe>
                                    <html>
                                        <head></head>
                                        <body>
                                        blah
                                        </body>
                                    </html>
                                </iframe>
                            </body>
                        </html>
                    </iframe>
                </body>
            </html>
        </iframe>
    </body>
</html>

However, there may be more - or less - iframes dependent upon the page and template I use.

I'm trying to therefore get the ID of all of the iframes in this page, from within the most-embedded iframe.

Is this possible with jQuery? I've tried a few snippets of code but had no luck:

$('iframe', window.parent.document).each(function() {
    console.log($(this).attr("id"));
});

$('iframe', parent.document).each(function() {
    console.log($(this).attr("id"));
});

$('iframe').each(function() {
    console.log($(this).attr("id"));
});

The output of these is a single ID string - and unfortunately it's not the iframe I'm looking to control.

Thanks in advance,

turbonerd
  • 1,234
  • 4
  • 27
  • 63

3 Answers3

3

EDITED

This returns an iframe element which has the wanted id, and null, if the wanted id is not found.

function searchIds(wantedId) {
    var idArray = [], n,
        search = function (iframes) {
            var n;
            for (n = 0; n < iframes.length; n++) {
                if (iframes[n].frames.length > 0) {
                    search(iframes[n].frames);
                }
                idArray.push(iframes[n].frameElement.id);
                idArray.push(iframes[n].frameElement);
            }
        };
    search(window.top.frames);
    for (n = 0; n < idArray.length; n += 2) {
        if (idArray[n] === wantedId) {
            return idArray[n + 1];
        }
    }
    return null;
}

Notice, that searchIds() can't be run before onload of the main window has been fired.

Teemu
  • 22,918
  • 7
  • 53
  • 106
  • Oh, sorry, one other thing (slightly off-topic) - I can see the ID of my iframe now, how do I go about "using" it? I.e. in jQuery I'd use something like `$('iframe#stuff', window.top.frames)` but that doesn't seem to do anything. – turbonerd Sep 19 '13 at 08:47
  • 1
    @dunc I was just about to ask you, how your'e goin to use that `id` : ). Just a second, I'll edit my answer. – Teemu Sep 19 '13 at 08:49
  • Teemu my friend you are a legend. I will give you some bounty points over the next couple of days for your extra efforts - many thanks. – turbonerd Sep 19 '13 at 09:03
  • this doesn't really answer the question (i am not contesting if it has valuable contents, though). `window.top.frames` only would answer, but it can generate a cross-origin acess. – ribamar Mar 05 '18 at 11:12
  • @ribamar This answers the question when all OP's comments are included in the question ... – Teemu Mar 05 '18 at 11:15
  • @Teemu Is this code still relevant in 2022? I'm trying to apply it in order to detect an iframe buried in a page but it is not working. I get: ```Uncaught TypeError: Cannot read properties of null (reading 'id')```. More details here: https://stackoverflow.com/questions/74215101/how-to-capture-iframe-after-all-page-elements-are-fully-loaded – Verminous Oct 27 '22 at 09:20
  • Yes, the code is still working. It looks like [`iframes[n].frameElement`](https://developer.mozilla.org/en-US/docs/Web/API/Window/frameElement) doesn't exist in your code. Make sure you don't iterate past the last index. If that's not the case, please ask a new question about your exact use-case. – Teemu Oct 27 '22 at 09:30
2

I do not believe you can reference the iframe's children directly. You will need to recursively search each iframe using it's .contents() call.

As far as I know, this will only work as long as the same-origin policy is not violated (i.e. the iframes must point to the same domain).

Maxim Kumpan
  • 2,545
  • 2
  • 19
  • 23
  • Sorry Maxim Kumpan, isn't that the wrong way round? I'm trying to manipulate the parent iframes from the most-embedded iframe (i.e. my widget is the "bottom" iframe). – turbonerd Sep 19 '13 at 08:38
0

From the most embedded iframe:

var ids = (function up( context, ids ){ 
   ids = ids || []; 
   // proceed if we're not at the top window yet
   if( context !== window.top){
      // point context to parent window (or top if no parent).
      context = context.parent || window.top; 
      // get the id of the first iframe in parent window; 
      // this will break if there are sibling iframes
      ids.push(context.document.getElementsByTagName('iframe')[0].id); 

      // recursive call to traverse parents          
      return up(context, ids); 
   } else {
      // otherwise return the list of ids
      return ids; 
   }
   }(this)); // 'this' is the initial context - current window

   console.log( ids );
pawel
  • 35,827
  • 7
  • 56
  • 53
  • Looks like this would find only one `iframe` per window. – Teemu Sep 19 '13 at 08:39
  • Trying to implement your code now but the `(this));` is returning a syntax error about a missing `;` before the `;`... doesn't make a lot of sense to me so I'm not sure how to fix it! – turbonerd Sep 19 '13 at 08:39
  • @dunc sorry, forgot a `}` after `else`, fixed now. – pawel Sep 19 '13 at 08:51
  • I'm afraid that only returns a single frame ID for me pawel. @Teemu's answer returns all of them (seven, oddly, on this page). – turbonerd Sep 19 '13 at 08:52
  • @dunc yes, Teemu's answer is great and probably does what you wanted, not what I thought you want ;) I traverse the tree up to find a chain od IDs from the most embedded frame up to the top window, while Teemu finds every iframe in the window regardless of relationship to the frame from which it's called. – pawel Sep 19 '13 at 08:57