Is there a function similar to jQuery
.closest()
but for traversing descendants and returning only closest ones?
I know that there is
The following plugin returns the nth closest descendants.
$.fn.getNthClosestDescendants = function(n, type) {
var closestMatches = [];
var children = this.children();
recursiveMatch(children);
function recursiveMatch(children) {
var matches = children.filter(type);
if (
matches.length &&
closestMatches.length < n
) {
var neededMatches = n - closestMatches.length;
var matchesToAdd = matches.slice(0, neededMatches);
matchesToAdd.each(function() {
closestMatches.push(this);
});
}
if (closestMatches.length < n) {
var newChildren = children.children();
recursiveMatch(newChildren);
}
}
return closestMatches;
};
Pure JS solution (using ES6).
export function closestDescendant(root, selector) {
const elements = [root];
let e;
do { e = elements.shift(); } while (!e.matches(selector) && elements.push(...e.children));
return e.matches(selector) ? e : null;
}
Considering the following structure:
div == $0 ├── div == $1 │ ├── div │ ├── div.findme == $4 │ ├── div │ └── div ├── div.findme == $2 │ ├── div │ └── div └── div == $3 ├── div ├── div └── div
closestDescendant($0, '.findme') === $2;
closestDescendant($1, '.findme') === $4;
closestDescendant($2, '.findme') === $2;
closestDescendant($3, '.findme') === null;
function closestDescendant(root, selector) {
const elements = [root];
let e;
do { e = elements.shift(); } while (!e.matches(selector) && elements.push(...e.children));
return e.matches(selector) ? e : null;
}
const [$0, $1, $2, $3, $4] = [0, 1, 2, 3, 4].map(x => document.querySelector(`#e${x}`));
console.log(closestDescendant($0, '.findme')); // $2
console.log(closestDescendant($1, '.findme')); // $4
console.log(closestDescendant($2, '.findme')); // $2
console.log(closestDescendant($3, '.findme')); // null
<div id="e0">
<div id="e1">
<div></div>
<div id="e4" class="findme"></div>
<div></div>
<div></div>
</div>
<div id="e2" class="findme">
<div></div>
<div></div>
</div>
<div id="e3">
<div></div>
<div></div>
<div></div>
</div>
</div>
What about this approach?
$('find-my-closest-descendant').find('> div');
This "direct child" selector works for me.
I was looking for a similar solution (I wanted all closest descendants, i.e. breadth first + all matches regardless of which level it exists), here's what I ended up doing:
var item = $('#find-my-closest-descendant');
item.find(".matching-descendant").filter(function () {
var $this = $(this);
return $this.parent().closest("#find-my-closest-descendant").is(item);
}).each(function () {
// Do what you want here
});
I hope this helps.