JavaScript: How to get parent element by selector?
JavascriptDomJavascript Problem Overview
Example:
<div someAttr="parentDiv. We need to get it from child.">
<table>
...
<td> <div id="myDiv"></div> </td>
...
</table>
</div>
I want to get the parent by some selector from the inner div element (the one with the myDiv
class).
How do I achieve that with plain JavaScript, without jQuery?
Something like:
var div = document.getElementById('myDiv');
div.someParentFindMethod('some selector');
Javascript Solutions
Solution 1 - Javascript
You may use closest()
in modern browsers:
var div = document.querySelector('div#myDiv');
div.closest('div[someAtrr]');
Use object detection to supply a polyfill or alternative method for backwards compatability with IE.
Solution 2 - Javascript
Here's the most basic version:
function collectionHas(a, b) { //helper function (see below)
for(var i = 0, len = a.length; i < len; i ++) {
if(a[i] == b) return true;
}
return false;
}
function findParentBySelector(elm, selector) {
var all = document.querySelectorAll(selector);
var cur = elm.parentNode;
while(cur && !collectionHas(all, cur)) { //keep going up until you find a match
cur = cur.parentNode; //go up
}
return cur; //will return null if not found
}
var yourElm = document.getElementById("yourElm"); //div in your original code
var selector = ".yes";
var parent = findParentBySelector(yourElm, selector);
Solution 3 - Javascript
Finds the closest parent (or the element itself) that matches the given selector. Also included is a selector to stop searching, in case you know a common ancestor that you should stop searching at.
function closest(el, selector, stopSelector) {
var retval = null;
while (el) {
if (el.matches(selector)) {
retval = el;
break
} else if (stopSelector && el.matches(stopSelector)) {
break
}
el = el.parentElement;
}
return retval;
}
Solution 4 - Javascript
This is using what leech talked about, but making it work for IE (IE doesn't support matches): Using leech's answer with indexOf (to support IE)
function closest(el, selector, stopSelector) {
var retval = null;
while (el) {
if (el.className.indexOf(selector) > -1) {
retval = el;
break
} else if (stopSelector && el.className.indexOf(stopSelector) > -1) {
break
}
el = el.parentElement;
}
return retval;
}
It's not perfect, but it works if the selector is unique enough so it won't accidentally match the incorrect element.
Solution 5 - Javascript
Here's a recursive solution:
function closest(el, selector, stopSelector) {
if(!el || !el.parentElement) return null
else if(stopSelector && el.parentElement.matches(stopSelector)) return null
else if(el.parentElement.matches(selector)) return el.parentElement
else return closest(el.parentElement, selector, stopSelector)
}
Solution 6 - Javascript
I thought I would provide a much more robust example, also in typescript, but it would be easy to convert to pure javascript. This function will query parents using either the ID like so "#my-element" or the class ".my-class" and unlike some of these answers will handle multiple classes. I found I named some similarly and so the examples above were finding the wrong things.
function queryParentElement(el:HTMLElement | null, selector:string) {
let isIDSelector = selector.indexOf("#") === 0
if (selector.indexOf('.') === 0 || selector.indexOf('#') === 0) {
selector = selector.slice(1)
}
while (el) {
if (isIDSelector) {
if (el.id === selector) {
return el
}
}
else if (el.classList.contains(selector)) {
return el;
}
el = el.parentElement;
}
return null;
}
###To select by class name:
let elementByClassName = queryParentElement(someElement,".my-class")
###To select by ID:
let elementByID = queryParentElement(someElement,"#my-element")
Solution 7 - Javascript
By using querySelector() and closest() methods is possible to get the parent element.
-
querySelector()
returns the first element that matches a specified CSS selector(s) in the document. -
closest()
searches up the DOM tree for the closest element which matches a specified CSS selector.
Usage example
var element = document.querySelector('td');
console.log(element.closest('div'));
<div>
<table>
<tr>
<td></td>
</tr>
</table>
</div>
In case of needing to select more than one element, querySelectorAll() is a good fit.
querySelectorAll()
returns all elements in the document that matches a specified CSS selector(s), as a static NodeList object.
To select the desired element, is necessary to specify it inside []
so, for example for the second element would be: element[1]
In the following example closest()
method is used to get the parent <tr>
element of an specific selected element.
var element = document.querySelectorAll('td');
console.log(element[1].closest('tr'));
<div>
<table>
<tr id="1">
<td> First text </td>
</tr>
<tr id="2">
<td> Second text </td>
</tr>
</table>
</div>
Solution 8 - Javascript
simple example of a function parent_by_selector which return a parent or null (no selector matches):
function parent_by_selector(node, selector, stop_selector = 'body') {
var parent = node.parentNode;
while (true) {
if (parent.matches(stop_selector)) break;
if (parent.matches(selector)) break;
parent = parent.parentNode; // get upper parent and check again
}
if (parent.matches(stop_selector)) parent = null; // when parent is a tag 'body' -> parent not found
return parent;
};
Solution 9 - Javascript
This is a simple way using recursion to get the parent with a specific class. You can modify it to switch depending on the selector, but the principle is the same:
function findParentByClass(child, parentClass) {
let parent = child.parentElement;
while(!(parent.className === parentClass)){
parent = findParentByClass(child.parentElement, parentClass)
}
return parent;
}
Solution 10 - Javascript
Here is simple way to access parent id
document.getElementById("child1").parentNode;
will do the magic for you to access the parent div.
<html>
<head>
</head>
<body id="body">
<script>
function alertAncestorsUntilID() {
var a = document.getElementById("child").parentNode;
alert(a.id);
}
</script>
<div id="master">
Master
<div id="child">Child</div>
</div>
<script>
alertAncestorsUntilID();
</script>
</body>
</html>
Solution 11 - Javascript
var base_element = document.getElementById('__EXAMPLE_ELEMENT__');
for( var found_parent=base_element, i=100; found_parent.parentNode && !(found_parent=found_parent.parentNode).classList.contains('__CLASS_NAME__') && i>0; i-- );
console.log( found_parent );