71

I am in the process of implementing jQuery, and taking out Prototype libraries in my codebase, and I am wondering if you could give me the best way to implement this functionality in jQuery. I am familiar with the jQuery ancestor>descendant syntax, but just want to check if an element is a descendant by true of false, like the code below: can someone give me the most efficient jQuery solution for this ?

<div id="australopithecus">
  <div id="homo-herectus">
    <div id="homo-sapiens"></div>
  </div>
</div>

$('homo-sapiens').descendantOf('australopithecus');
// -> true

$('homo-herectus').descendantOf('homo-sapiens');
// -> false
BenMorel
  • 34,448
  • 50
  • 182
  • 322
29er
  • 8,595
  • 12
  • 48
  • 65

11 Answers11

117

In jQuery 1.6, you can use the following code generically, e.g. targetElt and parentElt can both be DOM elements or jQuery-wrapped objects, as well as selectors:

$(targetElt).closest(parentElt).length > 0

Some of the other answers require you to refer to elements by their IDs, which isn't useful if all you have is a DOM element without an ID. Also, if you want to make sure that the targetElt is a strict descendant of parentElt (in other words, you don't want to count parentElt as its own descendant), make sure to add a targetElt != parentElt check before your call to .closest(), or use .parents().find() as Jonathan Sampson suggests.

Nathaniel
  • 1,362
  • 2
  • 9
  • 4
  • 2
    This should be the accepted answer. All the other answers in this question and the dup require knowing ID's / classes. This one is perfectly transparent to all of that – Daniel Magliola Jan 29 '13 at 13:34
  • 4
    0 is falsey so you can simply use $(targetElt).closest(parentElt).length as a condition. (ie without checking length is > 0) – ensignr Feb 10 '14 at 11:48
51

JQuery

With jQuery >=1.4 (2010) you can use the very fast function jQuery.contains()

This static method works with DOM elements, not with jQuery elements and returns true or false.

jQuery.contains( container, descendant )

Example: To check if a element is in the document you could do this:

jQuery.contains( document.body, myElement )

Native DOM

There is also a native DOM method Node.contains() that all browsers since ie5+ supports. So you can do it without jQuery:

document.body.contains( myElement )
Rúnar Berg
  • 4,229
  • 1
  • 22
  • 38
TLindig
  • 48,010
  • 3
  • 28
  • 31
  • 1
    You can use jQuery objects by pulling the DOM element from the object by adding "[0]" -> https://learn.jquery.com/using-jquery-core/faq/how-do-i-pull-a-native-dom-element-from-a-jquery-object/ – Dennis Heiden Nov 17 '16 at 04:35
  • 1
    This is the best answer, it doesn’t rely on the elements having unique selectors and—more importantly—it gives a non jquery solution. – Rúnar Berg Aug 02 '19 at 19:26
34

I would think you could take advantage of CSS style selection here, with returned length..

$('#australopithecus #homo-sapiens').length // Should be 1
$('#homo-sapiens #homo-herectus').length // Should be 0

Not exactly true/false, but checking 0/1 as a boolean should work. :)

Alternately, you could do something like $('#parent').find('#child') and check the length there.

Brian Arnold Sinclair
  • 3,833
  • 1
  • 21
  • 16
  • 1
    thanks for all the good answers!! i didn't realize i had so many options :) – 29er Jul 02 '09 at 06:55
  • 2
    Thank you! And you can "cast" these to `true`/`false` by prepending `!!`, like `!!$('#australopithecus #homo-sapiens').length`, which returns `true`. – Dmitry Minkovsky Mar 20 '13 at 18:11
  • 1
    There is no need to cast these to anything else since in javascript false, 0, null and NaN are all counted as false when used in if statements ... – Jonas Schubert Erlandsson Oct 24 '13 at 12:42
  • 1
    If you really want to get technical, it's more that those values are coerced to truthy or falsy values in comparisons. It's not really specifically in `if` statements or other conditionals. For example, if you were doing a strict comparison to `true`, you'd want to use the `!!` to coerce it youself into a proper boolean value. That being said, it's rare that people are doing that strict of a check. :) – Brian Arnold Sinclair Oct 28 '13 at 20:59
  • 1
    For what it's worth, the answer provided about using `.closest` is a better answer at this point to the question asked here. – Brian Arnold Sinclair Nov 15 '14 at 23:33
21

How about


$("#homo-herectus").parents().is("#australopithecus");
Matthew Groves
  • 25,181
  • 9
  • 71
  • 121
6

You can use the is() function like so:

alert($('#homo-sapiens').is('#australopithecus *'));
// -> true

alert($('#homo-herectus').is('#homo-sapiens *'));
// -> false
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
4
$.fn.descendantOf = function(element) {
    element = $(element)[0];
    var current = this;
    var body    = document.body;
    while (current && current != element && current != document.body) {
        current = $(current).parent()[0];
    }
    if (typeof(current) == "undefined" || typeof(current) == "null") {
        return false;
    } else if (current == element) {
        return true;
    } else if (current == document.body) {
        return false;
    }
}

Example:

<div id="foo">
    <div id="bar">
        <div id="baz"></div>
    </div>
</div>

And:

$('#foo').descendantOf('#bar');  // false
$('#foo').descendantOf('#foo');  // false
$('#foo').descendantOf(document.body);  // true
$('#bar').descendantOf('#foo');  // true
$('#baz').descendantOf('#foo');  // true
Hongli
  • 18,682
  • 15
  • 79
  • 107
  • `typeof` is not a function, it's a keyword. You don't need the parentheses, although it's still valid. `typeof current == "undefined"` – SeinopSys Jun 19 '13 at 16:14
3

You could attempt to .find() it in the Elements .children()

$("#lucy").find("#homo-erectus").length;

Or the opposite direction:

$("#homo-erectus").parents().find("#lucy").length;
Sampson
  • 265,109
  • 74
  • 539
  • 565
  • I don't know the jQuery syntax, but it would be quicker to check the parents() of the descendant item, rather than all the children of the ancestor, right? – harpo Jun 29 '09 at 17:32
  • @harpo, Potentially. Depending on users particular DOM. Good advice though - definitely something to consider. – Sampson Jun 29 '09 at 17:36
2

Best method that I found is using Dan G. Switzer, II's method found here: http://blog.pengoworks.com/index.cfm/2008/9/24/Using-jQuery-to-determine-if-an-element-is-a-child-of-another-element

jQuery.fn.isChildOf = function(b){ 
    return (this.parents(b).length > 0); 
};

Then you would just use the plugin as:

$('homo-sapiens').isChildOf('australopithecus');
// -> true

$('homo-herectus').isChildOf('homo-sapiens');
// -> false
Serj Sagan
  • 28,927
  • 17
  • 154
  • 183
0

An alternative to closest() that uses (almost) the same traverse principle and doesn't include the element itself: child.parentsUntil(ancestor).last().parent().is(ancestor).

var child = $('#homo-sapiens');
var ancestor = $('#australopithecus');

console.log(child.parentsUntil(ancestor).last().parent().is(ancestor)); // true
Ian Bytchek
  • 8,804
  • 6
  • 46
  • 72
-1
function descendantOf(parentId, childId) {
   return ( $('#'+parentId+' > #'+childId).length === 1 );
}

That should work.

As was pointed out in the comment below, if you don't want it to be just direct descendants:

function descendantOf(parentId, childId) {
   return ( $('#'+childId, $('#'+parentId)).length === 1 );
}
Thomas
  • 4,889
  • 4
  • 24
  • 19
  • 3
    The use of the > character in the selector will limit the check to only first-generation decdendants. If you want to check to see if its any kind of descendant (as opposed to direct descendant) then simply remove the > character. – Ken Browning Jun 29 '09 at 17:43
-1

Supposing to rewrite your initial statement in:

$('#homo-sapiens').descendantOf('#australopithecus');

try to plugin:

(function($) {
    $.fn.descendantOf = function(parentId) {
        return this.closest(parentId).length != 0;
    }
})(jQuery)
tanathos
  • 5,566
  • 4
  • 34
  • 46