powerboy
powerboy

Reputation: 10961

How to find the closest descendants (that matches a selector) with jQuery?

We can use closest(selector) to find the first ancestor element that matches the selector. It travels up the DOM tree until it finds a match for the selector. But what if I want to travels down the DOM tree until it finds a match for the selector? Is there any jQuery function for doing this? Or do I need to implement this using breadth-first search?

Give an example. For the DOM tree below,

<div id="main">
    <div>
        <ul><!-- I want to match this ul -->
            <li>
                <ul><!-- but not this ul -->
                </ul>
            </li>
        </ul>
        <ul><!-- and match this ul -->
        </ul>
    </div>
</div>

how to do something like $('#main').closestDescendants('ul')?

Upvotes: 5

Views: 2318

Answers (4)

Nathan Bubna
Nathan Bubna

Reputation: 6933

So, the closestChild plugin links are broken for me. Here's an implementation:

$.fn.nearest = function(selector) {
    var nearest = $(), node = this, distance = 10000;
    node.find(selector).each(function(){
        var n = $(this),
            d = n.parentsUntil(node).size();
        if (d < distance) {
            distance = d;
            nearest = n;
        } else if (d == distance) {
            nearest = nearest.add(this);
        }
    });
    return nearest;
};

Upvotes: 1

jiggy
jiggy

Reputation: 3826

I had the same issue and needed a much more generic solution, so I wrote a function for it and decided to package it up as a jQuery plugin. I know this thread is pretty old, but please have a look and let me know what you think.

Upvotes: 0

CurtainDog
CurtainDog

Reputation: 3205

Something like this might suffice:

$('#main ul:not(#main ul ul)')

If you need something more accurate then you can use each() to iterate the list of elements, calculate the shortest path to #main, and filter out those elements where the path is longer than this.

Upvotes: 0

Zachary
Zachary

Reputation: 6532

Will the elements you want to match always be a child of a div? If so, you could match using .children('ul') syntax. It would be best to put a Id/Class on the div, so you could do the following...

$('#menu').children('ul');

<div id="main">
    <div id="menu">
        <ul><!-- I want to match this ul -->
            <li>
                <ul><!-- but not this ul -->
                </ul>
            </li>
        </ul>
        <ul><!-- and match this ul -->
        </ul>
    </div>
</div>

Upvotes: 0

Related Questions