Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Similar to jQuery .closest() but traversing descendants?

Tags:

jquery

If by "closest" descendant you mean the first child then you can do:

$('#foo').find(':first');

Or:

$('#foo').children().first();

Or, to look for the first occurrence of a specific element, you could do:

$('#foo').find('.whatever').first();

Or:

$('#foo').find('.whatever:first');

Really though, we need a solid definition of what "closest descendant" means.

E.g.

<div id="foo">
    <p>
        <span></span>
    </p>
    <span></span>
</div>

Which <span> would $('#foo').closestDescendent('span') return?


According to your definition of closest, I've written the following plugin:

(function($) {
    $.fn.closest_descendent = function(filter) {
        var $found = $(),
            $currentSet = this; // Current place
        while ($currentSet.length) {
            $found = $currentSet.filter(filter);
            if ($found.length) break;  // At least one match: break loop
            // Get all children of the current set
            $currentSet = $currentSet.children();
        }
        return $found.first(); // Return first match of the collection
    }    
})(jQuery);

You can use find with the :first selector:

$('#parent').find('p:first');

The above line will find the first <p> element in the descendants of #parent.


What about this approach?

$('find-my-closest-descendant').find('> div');

This "direct child" selector works for me.


In case someone's looking for a pure JS solution (using ES6 instead of jQuery), here's the one I use:

Element.prototype.QuerySelector_BreadthFirst = function(selector) {
    let currentLayerElements = [...this.childNodes];
    while (currentLayerElements.length) {
        let firstMatchInLayer = currentLayerElements.find(a=>a.matches && a.matches(selector));
        if (firstMatchInLayer) return firstMatchInLayer;
        currentLayerElements = currentLayerElements.reduce((acc, item)=>acc.concat([...item.childNodes]), []);
    }
    return null;
};