Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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();
      });
    }
like image 770
Nathan Boaldin Avatar asked Aug 25 '18 23:08

Nathan Boaldin


2 Answers

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>
like image 174
Scott Marcus Avatar answered Sep 29 '22 16:09

Scott Marcus


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)
like image 31
Roman Karagodin Avatar answered Sep 29 '22 16:09

Roman Karagodin