What JQuery selector excludes items with a parent that matches a given selector?

Dan Davies Brackett picture Dan Davies Brackett · Jun 8, 2009 · Viewed 33k times · Source

I have

var $set = $('.foo,.bar').filter(
    function() {return $(this).parents('.baz').length < 1;});

as a way to select all the elements whose classes are either foo or bar and who do not descend from an element whose class is baz. Is there a selector that will accomplish the same thing without the need for a filtering lambda?

<div class='foo'/><!--match this-->
<div class='bar'/><!--match this-->
<div class='baz'>
    <div class='foo'/> <!--don't match this-->
</div>

Answer

Paolo Bergantino picture Paolo Bergantino · Jun 8, 2009

The truth of the matter is that jQuery simply does not have a particularly elegant way to do what you want. While chaos' answer does work, you have to wonder whether the complicated selector (that would be about as slow as a selector can be in a complicated webpage) is worth it over the more verbose but faster filter function you have. This is not really that big of a deal, I am just personally weary of particularly long, convoluted selectors when I can avoid it.

A different option is to create your own selector, since jQuery is awesome:

jQuery.expr[':'].parents = function(a,i,m){
    return jQuery(a).parents(m[3]).length < 1;
};

$('.foo,.bar').filter(':parents(.baz)');

The expr map is part of the Sizzle selector engine and documentation can be found here: Sizzle Custom Pseudo-Selectors