How to check in Javascript if one element is contained within another
You should use Node.contains
, since it's now standard and available in all browsers.
https://developer.mozilla.org/en-US/docs/Web/API/Node.contains
Update: There's now a native way to achieve this. Node.contains()
. Mentioned in comment and below answers as well.
Old answer:
Using the parentNode
property should work. It's also pretty safe from a cross-browser standpoint. If the relationship is known to be one level deep, you could check it simply:
if (element2.parentNode == element1) { ... }
If the the child can be nested arbitrarily deep inside the parent, you could use a function similar to the following to test for the relationship:
function isDescendant(parent, child) {
var node = child.parentNode;
while (node != null) {
if (node == parent) {
return true;
}
node = node.parentNode;
}
return false;
}
I just had to share 'mine'.
Although conceptually the same as Asaph's answer (benefiting from the same cross-browser compatibility, even IE6), it is a lot smaller and comes in handy when size is at a premium and/or when it is not needed so often.
function childOf(/*child node*/c, /*parent node*/p){ //returns boolean
while((c=c.parentNode)&&c!==p);
return !!c;
}
..or as one-liner (just 64 chars!):
function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}
and jsfiddle here.
Usage:childOf(child, parent)
returns boolean true
|false
.
Explanation:while
evaluates as long as the while-condition evaluates to true
.
The &&
(AND) operator returns this boolean true/false after evaluating the left-hand side and the right-hand side, but only if the left-hand side was true (left-hand && right-hand
).
The left-hand side (of &&
) is: (c=c.parentNode)
.
This will first assign the parentNode
of c
to c
and then the AND operator will evaluate the resulting c
as a boolean.
Since parentNode
returns null
if there is no parent left and null
is converted to false
, the while-loop will correctly stop when there are no more parents.
The right-hand side (of &&
) is: c!==p
.
The !==
comparison operator is 'not exactly equal to'. So if the child's parent isn't the parent (you specified) it evaluates to true
, but if the child's parent is the parent then it evaluates to false
.
So if c!==p
evaluates to false, then the &&
operator returns false
as the while-condition and the while-loop stops. (Note there is no need for a while-body and the closing ;
semicolon is required.)
So when the while-loop ends, c
is either a node (not null
) when it found a parent OR it is null
(when the loop ran through to the end without finding a match).
Thus we simply return
that fact (converted as boolean value, instead of the node) with: return !!c;
: the !
(NOT
operator) inverts a boolean value (true
becomes false
and vice-versa).!c
converts c
(node or null) to a boolean before it can invert that value. So adding a second !
(!!c
) converts this false back to true (which is why a double !!
is often used to 'convert anything to boolean').
Extra:
The function's body/payload is so small that, depending on case (like when it is not used often and appears just once in the code), one could even omit the function (wrapping) and just use the while-loop:
var a=document.getElementById('child'),
b=document.getElementById('parent'),
c;
c=a; while((c=c.parentNode)&&c!==b); //c=!!c;
if(!!c){ //`if(c)` if `c=!!c;` was used after while-loop above
//do stuff
}
instead of:
var a=document.getElementById('child'),
b=document.getElementById('parent'),
c;
function childOf(c,p){while((c=c.parentNode)&&c!==p);return !!c}
c=childOf(a, b);
if(c){
//do stuff
}
Another solution that wasn't mentioned:
Example Here
var parent = document.querySelector('.parent');
if (parent.querySelector('.child') !== null) {
// .. it's a child
}
It doesn't matter whether the element is a direct child, it will work at any depth.
Alternatively, using the .contains()
method:
Example Here
var parent = document.querySelector('.parent'),
child = document.querySelector('.child');
if (parent.contains(child)) {
// .. it's a child
}
You can use the contains method
var result = parent.contains(child);
or you can try to use compareDocumentPosition()
var result = nodeA.compareDocumentPosition(nodeB);
The last one is more powerful: it return a bitmask as result.