Sylvain
Sylvain

Reputation: 19249

How to select children elements but only one level deep with jQuery

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

Answers (3)

Tofandel
Tofandel

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

Sandro Pasquali
Sandro Pasquali

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

Sampson
Sampson

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

Related Questions