jQuery "hasParent"

The JQuery "has" method effectively selects all elements where they have particular descendants.

I want to select elements based on the fact they have particular ancestors. I know about parent([selector]) and parents([selector]) but these select the parents and not the children with the parents.

So is there an ancestor equivalent of "has"?

Note: I already have the context of an element further down the hierarchy and I will be selecting based on this so I can't do a "top down" query.

Update

I've obviously explained myself really badly here, so I'll try and clarify:

<ul class="x">
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>
<ul class="y">
  <li>4</li>
  <li>5</li>
  <li>6</li>
</ul>

I have a jQuery object that already consists of elements 2,3,4 and 5. I want to select those elements who have a parent with the class = x.

Hope that makes more sense.


Solution 1:

For a clean re-usable solution, consider extending the jQuery.fn object with a custom method used for determining the presence of a particular ancestor for any given element:

// Extend jQuery.fn with our new method
jQuery.extend( jQuery.fn, {
    // Name of our method & one argument (the parent selector)
    within: function( pSelector ) {
        // Returns a subset of items using jQuery.filter
        return this.filter(function(){
            // Return truthy/falsey based on presence in parent
            return $(this).closest( pSelector ).length;
        });
    }
});

This results in a new method, $.fn.within, that we can use to filter our results:

$("li").within(".x").css("background", "red");

This selects all list items on the document, and then filters to only those that have .x as an ancestor. Because this uses jQuery internally, you could pass in a more complicated selector:

$("li").within(".x, .y").css("background", "red");

This will filter the collection to items that descend from either .x or .y, or both.

Fiddle: http://jsfiddle.net/jonathansampson/6GMN5/

Solution 2:

if ( $('.foo').parents('.parentSelector').length ) { // has parent }

Solution 3:

If I understand your question correctly, this would do:

$.fn.hasAncestor = function(a) {
    return this.filter(function() {
        return !!$(this).closest(a).length;
    });
};

$('.element').hasAncestor('.container').myAction();

<div class="container">
  <span>
    <strong class="element">strong</strong>
  </span>
</div>

Solution 4:

$('body').hasParent('html') //true

$('div#myDiv').hasParent($('body')) //true

#API:

// check if current element has parent element 'e' 
$.fn.hasParent = function (e) {
    return !!$(this).parents(e).length
}

Solution 5:

You can actually use filter directly (without a function calling closest) and it will have better performance. Simply use a selector that matches elements contained within .x:

$("li").filter(".x *")

this also differs slightly from the closest solutions suggested by others in that it will not match if the element itself has the given class but only if it is within an element with that class.

If matching an element with the class is desired as well, this could be modified slightly:

$("li").filter(".x, .x *")

$("li").filter(".x *").css("background", "red");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="x"><li>1</li><li>2</li><li>3</li></ul>
<ul class="y"><li>4</li><li>5</li><li>6</li></ul>