Get iframe contents with a jquery selector
Asked Answered
A

4

11

Is there anyway to access an iframe's contents via a selector? Something like this:

$("iframe::contents .my-foo")

I'm constantly accessing an iframe's contents for a project I'm currently working on and $("iframe").contents().find(".my-foo") is becoming a bit tedious to type out.

If this feature doesn't exist in jquery out of the box, is there a plugin that provides this functionality? If not how could I write such a plugin?

Andee answered 13/5, 2011 at 13:42 Comment(0)
S
18

I had this issue once where I found it tedious. I never found a solution for how to write a single selector like that.

Even so, the selector is still rather long. The most obvious solution to me is just save it to a variable.

var frame = $("iframe").contents();

frame.find(".my-foo")
...

Is that better?

Sunbeam answered 13/5, 2011 at 13:49 Comment(1)
Some More Info - contents() = children() + plaintext . Some may be thinking what is the use of contents() when we could just use $('iframe').find('.my-foo'), then please read The contents() method can also access the HTML of an iframe, if it is in the same domain. from w3schools.com/jquery/traversing_contents.aspNierman
G
2

Intuitively, it seems more elegant to pack everything into the one selector, but the truth is that, even if there were such a selector, it is better from a performance perspective to traverse with find(). Then jQuery doesn't have to parse and analyze the string.

Gog answered 13/5, 2011 at 13:52 Comment(0)
A
1

Added here for posterity. The solution I ended up going with was to override the root jquery object with a bit of custom parsing code. Something like this:

(function() {
    var rootjq = window.jQuery;

    var myjq = function(selector, context) {
        if(selector.indexOf("::contents") === -1) {
            return rootjq(selector, context);
        } else {
            var split = selector.split("::contents");

            var ifrm = split[0];
            var subsel = split.splice(1).join("::contents");

            var contents = rootjq(ifrm, context).contents();

            // Recursive call to support multiple ::contents in a query
            return myjq(subsel, contents);
        }
    };
    myjq.prototype = myjq.fn = rootjq.fn;

    window.jQuery = window.$ = myjq;
})();

Note that double colon (::) in css means select pseudo element, while single colon means select by pseudo class.

Andee answered 27/8, 2015 at 15:18 Comment(0)
T
0

You can create your own custom selector. Like:

$.extend($.expr[':'], {
    contents: function(elem, i, attr){
      return $(elem).contents().find( attr[3] );
    }
});  

Usage should be like

$('iframe:contents(.my-foo)').remove(); 
Tb answered 13/5, 2011 at 13:52 Comment(2)
Out of curiosity why are using $.extend? Why not add the property directly like this: $.expr[":"].contents = function(...) { ... }?Andee
This answer doesn't work. I was looking for a replacement of $("iframe").contents().find(".my-foo"). Functions hanging off of $.expr[':'] act like filters.Andee

© 2022 - 2024 — McMap. All rights reserved.