How to get parent multiple levels up the DOM tree without jQuery or modifying Element.prototype?
Asked Answered
J

3

10

I am wondering if there is a way to select a specific element way up the DOM only using vanilla JS while not having to use parentNode multiple times. I understand you can do this with jQuery and modifying Element.prototype, but are there any other pretty ways to write this.

  const deleteButtons = document.querySelectorAll('.delete-button');

  for (var i = 0; i < deleteButtons.length; i++) {
    deleteButtons[i].addEventListener('click', (e) => {
      e.preventDefault();

      //This is the crazy amount of parentNode usage
      bookDatabase.child(e.target.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.getAttribute("id")).remove();
      });
    }
Jumbo answered 25/8, 2018 at 23:14 Comment(3)
You can use a for loop with a fixed number of iterations or use an id or class name to retrieve the element if possible.Microcline
You want a function that takes an element and a number and return the parent element at "number" of levels up?Dotterel
These are great ideas, but I should have been more clear that I was looking for an existing method. Thank you.Jumbo
C
26

There is really only one other way, which is to use the DOM API element.closest(), but it does require that you provide a selector that can uniquely identify the particular element you need (or the first element that matches that selector from the descendant's point of view). Without that, multiple uses of the .parent() method would be required and you'd need to know how many levels up you want to go.

// Starting from the inner most level
var start = document.getElementById("source");

// Let's say you wanted to reference the first ancestor
// that has the "something3" class
start.closest(".something3").classList.add("red");

// Or, the second closest
var firstMatch = start.closest(".something2");
firstMatch.classList.add("yellow");

// Or, even higher
firstMatch.closest(".something1").classList.add("aqua");

// And, of course, you can skip levels
start.closest(".something1").classList.add("dropCap");
#source {background-color:orange; }
.red { background-color:red; }
.yellow { background-color:yellow; font-size:1rem; }
.aqua { background-color:aqua; }
.dropCap { font-size:3em; }
<div class="something1">Level 1
  <div class="something2">Level 2
    <div class="something3">Level 3
      <div id="source">Level 4</div>
    </div>  
  </div>
</div>
Cairn answered 25/8, 2018 at 23:31 Comment(2)
This is what I am looking for. I think I have seen element.closest() before, but I assumed it was jQuery. Good to know. Thank you.Jumbo
This is looking good and neet. Its slove my issue. Big thanksSecateurs
G
5

I ran into the same issue... This helped me a lot

You can just traverse to the specific Parent Element you want by using

element.closest('.parentClass') - or - element.closest('#parentId')

Where 'element' is the origin element (in your case 'e.target'), and

'parentClass' - or - 'parentID' is the identifier of the parent Element you want.

Gader answered 9/6, 2020 at 11:43 Comment(0)
L
5

Here is the simplest way to get a parent node of a needed hierarchical level:

function getParentNode(element, level = 1) { // 1 - default value (if no 'level' parameter is passed to the function)
    while (level-- > 0) {
      element = element.parentNode;
      if (!element) return null; // to avoid a possible "TypeError: Cannot read property 'parentNode' of null" if the requested level is higher than document
    }
    return element;
}

With this function, instead of:

e.target.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode

you can use this:

getParentNode(e.target, 6)
Louvain answered 13/1, 2021 at 18:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.