admin管理员组文章数量:1129090
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');
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');
Share
Improve this question
edited Oct 16, 2023 at 13:34
TylerH
21.2k76 gold badges79 silver badges110 bronze badges
asked Jan 9, 2013 at 11:48
nkuhtankuhta
11.1k12 gold badges44 silver badges55 bronze badges
5
|
14 Answers
Reset to default 397You 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.
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);
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;
}
By using querySelector() and closest() methods is possible to get the parent element.
querySelector()
returns the first element that match 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
const 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 match 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.
const el = document.querySelectorAll('td')
console.log(el[1].closest('tr'))
<div>
<table>
<tr id="1">
<td> First text </td>
</tr>
<tr id="2">
<td> Second text </td>
</tr>
</table>
</div>
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.classList.contains(parentClass))){
parent = findParentByClass(child.parentElement, parentClass)
}
return parent;
}
Using leech's answer with indexOf (to support IE)
This is using what leech talked about, but making it work for IE (IE doesn't support matches):
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.
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)
}
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")
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;
};
/* --------------------------------------------------
get a parent element by its id or classname
[child] - the element were starting with
[idOrClassName] - id or classname of parent element
were looking for
------------------------------------------------- */
function getParent(child, idOrClassName = ""){
while(child.tagName.toLowerCase() != "body"){
// get the next parent up
child = child.parentNode;
// we reached body tag which means parent element with
// class or id of [idOrClassName] not found so exit
if(child.tagName.toLowerCase() == "body"){
return false;
}
// if the id of this element = [idOrClassName] or .classList
// of [child] contains [idOrClassName], weve found our element
if((child.id == idOrClassName) || (child.classList.contains(idOrClassName))){
return child;
}
}
}
I believe this is best solved with a recursive function. The following one-liner function uses a ternary expression and a coalescing operator to recursively search each parent in a chain of direct ancestors until the first parentElement
is found which satisfies the given selector. If none are found by the time the recursive probing reaches the document
, result is undefined
.
/** finds the first direct ancestor matching the provided selector. */
const probeSelector = (child, selector) =>
!selector || !child || !child.parentElement ? undefined
: (child.parentElement.querySelectorAll(selector).values().find(x => x === child)
?? probeSelector(child.parentElement, selector));
As of "baseline 2023" there's a new :has
CSS pseudo-class which should do the trick:
https://developer.mozilla.org/en-US/docs/Web/CSS/:has
Given the structure in the original question:
<div someAttr="parentDiv. We need to get it from child.">
<table>
...
<td> <div id="myDiv"></div> </td>
...
</table>
</div>
The following should work (if I didn't make a mistake - I was experimenting/testing with a different page):
document.querySelector('div[someAttr]:has(#myDiv)')
- should select the top-leveldiv[someAttr]
.document.querySelector('[someAttr]:has(>#myDiv)')
- should fail to select anything, because it requires theid="myDiv"
element to be an immediate child of an element with thesomeAttr
attribute.document.querySelector(':has(>#myDiv)')
- selects the immediate parent of thediv#myDiv
element.
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>
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 );
本文标签: javascriptHow to get parent element by selectorStack Overflow
版权声明:本文标题:javascript - How to get parent element by selector - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736735315a1950221.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
element.parentNode
or if it needs to match a query, something likeelement.parentNode.matches('.some-query') ? element.parentNode : null
– user56reinstatemonica8 Commented Nov 29, 2022 at 12:55