Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery: highest level elements that contain x

I'm looking for a way to select elements that contain a certain element and then filter the results to get only the highest level. Difficult to explain but made easier with an example:

<div id="one">
    <div id="two">
        <div id="three" class="find-me"></div>
    </div>
</div>
<div id="four">
    <div id="five" class="find-me"></div>
</div>

In this case, I would want my set to contain #one and #four. If I try to do something like this:

var elements = $('div').has('.find-me');

I get elements #one, #two and #four.

Note: By 'highest level' relates to the topmost element in the first selector, $('div') in this case.

like image 420
ajbeaven Avatar asked Nov 10 '11 23:11

ajbeaven


4 Answers

Well the definition of what the highest level is, is a bit ambiguous because in practice if there is any .find-me in your page the highest level parent would be html tag! which is useless.

By defining your problem more specifically you can come up with a clearer definition for this highest-definition and for example say the farthest div parent et. and in order to traverse parents of an element you can use .parents() and .closest() methods.

var farthestDiv = $(".find-me").parents("div").last();

obviously if you have more than one occurances of find-me you need to run this in a .each() loop.

see an example here: http://jsfiddle.net/GsQDb/3/

like image 68
Mo Valipour Avatar answered Nov 18 '22 00:11

Mo Valipour


Assuming by "top level", you mean a direct descendant of the body tag, you can use this one liner. It finds all objects with a .find-me class, then searches the parents for a tag that is a descendant of the body tag (which will be the top level).

$(".find-me").parents("body > *")

You can see it work here: http://jsfiddle.net/jfriend00/9LF6u/

This has these advantages:

  1. Any type of tag can be the top level tag (not just a div)
  2. It should be one of the faster ways to do it since it finds the .find-me objects (which will be a fast operation internally in most browsers via getElementsByClassName) and just walks up their parent hierarchy.
  3. It automatically handles duplicates so a given top level item will never be listed more than once.
  4. If ever you want to change the definition of top level (to a container object, for example), you can just change the selector passed to the .parents(selector) method to reflect that change.
like image 31
jfriend00 Avatar answered Nov 18 '22 02:11

jfriend00


use filter to filter out elements that don't match what you want after your first selector. example:

var elements = $('div.find-me').filter(function(idx){ 
    return !$(this).parents('div.find-me').length;
});
like image 1
karnyj Avatar answered Nov 18 '22 02:11

karnyj


This will do what you want, it will find the elements first and then find the highest elements of those and create a jQuery object of the found highest elements.

var elements = $('div.find-me'), highest = [];

elements.each( function(){
var parent = this, body = document.body;

    while( parent && parent.parentNode !== body ) {
    parent = parent.parentNode;
    }

    if( $.inArray( parent, highest ) < 0 ) {
    highest.push( parent );
    }
});

highest = jQuery( highest );

jsfiddle:

http://jsfiddle.net/D3jC8/2/

like image 1
Esailija Avatar answered Nov 18 '22 01:11

Esailija