Reputation: 19249
Given this:
<div id="div1">
<div id="div2">
<div id="div200">
<div id="div3" class="b">
</div>
<div id="div300">
<div id="div4" class="b">
<div id="div5">
<div id="div6" class="b">
</div>
</div>
</div>
<div>
<div>
<div>
</div>
I need a way to find the children (deep) of an element that are of class "b" but not those that are nested inside a matched element.
Test cases:
This is what I need:
Case 1:
$("#div1").some_jquery_syntax(".b")
Should return:
div3, div4
Case 2:
$("#div5").some_jquery_syntax(".b")
Should return:
div6
Note that the hard part is that I have have to skip div2 when starting from div1. So I can't just use $("#div1").find("> .b")
.
My attempts:
I tried this:
$("#div1").find(".b")
[<div id="div3" class="b"></div>, <div id="div4" class="b"></div>, <div id="div5" class="b"></div>]
Not good: I don't want div5 because it is nested inside div4.
I tried this:
$("#div0").find(".b").not(".b .b")
[<div id="div3" class="b"></div>, <div id="div4" class="b"></div>]
Which is ok when starting with div0, but it does not work stating from div4:
$("#div5").find(".b").not(".b .b")
[]
Upvotes: 22
Views: 21529
Reputation: 3565
You were not far from the fastest solution, the problem with
$("#div5").find(".b").not(".b .b")
Is that the .not
is not relative to your initial selector (eg: #div5
) and since there is a .b
parent to #div6
in the DOM tree it will be excluded (the parent being #div4
)
The solution is then to make your .not
relative to your selector
This will correctly select #div6
:
$("#div4").find(".b").not("#div4 .b .b")
This will correctly select #div3
and #div4
:
$("#div1").find(".b").not("#div1 .b .b")
You might also be interested in this recursive iterator function
It will call a callback function with the current element and depth as parameter, the recursion can be done ascendant or descendant using the asc parameter and you can also specify a max depth of recursion
In desc mode if your callback return false the iteration immediatly stops
Upvotes: 2
Reputation: 51
General (when only class can be guaranteed):
$("#div1").find(".b:not(.b .b)")
As described (likely faster than general, though not tested):
$("#div1").find("div.b:not(div.b div.b)")
"All .b which are not descendants of .b"
Upvotes: 5
Reputation: 268334
Find the immediate grand-children:
$("#div1").children().children(".b");
Fiddle: http://jsfiddle.net/jonathansampson/Dy6GJ/
If you don't know how deep to go, but want all .b
not within a .b
, use a filter while respecting parent limitations. You could use the .parentsUntil
method:
var parent = "#div1";
$(".b", parent).filter(function(){
return !$(this).parentsUntil(parent, ".b").length;
}).css("border", "1px solid red");
Fiddle: http://jsfiddle.net/jonathansampson/Dy6GJ/3/
Upvotes: 17