Find an ancestor with a given class from any descendant element with pure JavaScript

2

With jQuery it is quite simple to find an ancestral element that has a given class, id, attribute, and so on. using the .closest() method. For example, in the code below I can select div#principal by clicking on any of your descendants:

$("#principal *").on("click", function(evt){

   var elemento_clicado = $(evt.target)[0];
   var ancestral = $(evt.target).closest("#principal")[0];
   console.log(elemento_clicado, ancestral);

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script><divid="principal">
  <div>Texto</div>
  <h3>titulo</h3>
  <strong>negrito</strong>
  <div>
    <p>sub-elemento</p>
    <div>
      <ul>
        <li>Lista 1</li>
      </ul>
    </div>
  </div>
</div>

No matter the level within the% w / w of the element, #principal will fetch the element entered in the selector (in this case the .closest(seletor) ).

I do not know a JavaScript method that does this function. I thought about using div#principal but since the nested elements inside the main div can have 1, 2, 3 or multiple levels in the tree, I would not know how many .parentNode to use when clicking on an element in level 1 or level 5, for example.

I came to this code that returns the clicked element to me:

var itens = document.querySelectorAll("#principal .item");
for(var x=0; x < itens.length; x++){
   
   itens[x].onclick = function(evt){
      console.log(evt.target);
   }
   
}
.item{
   background: orange;
   margin-bottom: 1px;
}

.item *{
   background: red;
}
<div id="principal">
   <div class="item">
      <p>
         <strong>Texto 1</strong>
      </p>
   </div>
   <div class="item">
      <h3>Título</h3>
      <p>
         <strong>Texto 2</strong>
      </p>
   </div>
   <div class="item">
      <h3>Título</h3>
      <p>
         <strong>Texto 3</strong>
      </p>
      <div class="item2">
         <div>
            <p>
               Texto 4 <strong>mais...</strong>
            </p>
         </div>
      </div>
   </div>
</div>

In the above hypothetical example, how would I go about getting to the div with the .parentNode class when clicking on any of its descendants, just like jQuery .item ?

    
asked by anonymous 29.11.2018 / 23:58

1 answer

2

At this point pure JS also has a closest equal to that of JQuery. This also gets a selector and is a Element method, which in this case will be an element that you have obtained from the DOM. See the documentation .

In your code, then:

evt.target.closest(".item")

Example:

var itens = document.querySelectorAll("#principal .item");
for(var x=0; x < itens.length; x++){
   
   itens[x].onclick = function(evt){
      var elemento_clicado = evt.target;
      var ancestral = evt.target.closest(".item");
      console.log(elemento_clicado, ancestral);
   }
   
}
.item{
   background: orange;
   margin-bottom: 1px;
}

.item *{
   background: red;
}
<div id="principal">
   <div class="item">
      <p>
         <strong>Texto 1</strong>
      </p>
   </div>
   <div class="item">
      <h3>Título</h3>
      <p>
         <strong>Texto 2</strong>
      </p>
   </div>
   <div class="item">
      <h3>Título</h3>
      <p>
         <strong>Texto 3</strong>
      </p>
      <div class="item2">
         <div>
            <p>
               Texto 4 <strong>mais...</strong>
            </p>
         </div>
      </div>
   </div>
</div>

As you might expect, there is no support for the mythical IE, however, there is a polyfill on the documentation page itself if you need it.

    
30.11.2018 / 02:07