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
  • 4 Google give only jQuery.parent everywhere. – nkuhta Commented Jan 9, 2013 at 15:10
  • Possible duplicate of Find the closest ancestor element that has a specific class – Vadzim Commented Dec 8, 2016 at 14:54
  • 1 Please update selected answer per suggestion from @soullivaneuh below. – vhs Commented Sep 2, 2018 at 9:54
  • Jquery closest for people who don't have the constraint of not using JQuery - api.jquery.com/closest – Sahil Singh Commented Jun 13, 2021 at 19:29
  • Note that this question is looking for ancestor elements matching a query; for anyone looking for only the parent element, try element.parentNode or if it needs to match a query, something like element.parentNode.matches('.some-query') ? element.parentNode : null – user56reinstatemonica8 Commented Nov 29, 2022 at 12:55
Add a comment  | 

14 Answers 14

Reset to default 397

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.

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-level div[someAttr].
  • document.querySelector('[someAttr]:has(>#myDiv)') - should fail to select anything, because it requires the id="myDiv" element to be an immediate child of an element with the someAttr attribute.
  • document.querySelector(':has(>#myDiv)') - selects the immediate parent of the div#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