YannB
YannB

Reputation: 83

How to add one event listener for nested elements

I have the HTML below:

<!DOCTYPE html>
        <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <meta charset="utf-8" />
            <title></title>
        </head>
        <body>
            <div>
                <section>
                    <a>first</a>
                    <a>second</a>
                </section>
            </div>
            <section>
                <a>third</a>
                <a>fourth</a>
            </section>
            <section>
                <div>
                    <a>fifth</a>
                    <a>sixth</a>
                </div>
            </section>
        <script src="ex-2-a.js"></script>
        <!--<script src="ex-2-b.js"></script>-->
        </body>
        </html>

I'm looking to add only one event listener to the whole document that would catch only 'a' tags that have a 'div' as ancestors. This means that if I click first, second, fifth and sixth I would get a message saying "cool".

Any ideas on that matter since there's no id and working with only tagnames?

Upvotes: 1

Views: 2365

Answers (2)

YannB
YannB

Reputation: 83

Thanks to @Scott Marcus for helping out. I submitted the answer and it worked. I also found a new approach using .closest(). let me know your thoughts

document.addEventListener('click',(e)=>{
let currElm = e.target;
if (currElm.closest('div')) {
  console.log(currElm);
 }
});

Upvotes: 1

Scott Marcus
Scott Marcus

Reputation: 65796

Using "event delegation" (setting an event handler on an element high up in the DOM tree and allowing events from elements lower in the tree to bubble up and be caught), we can set up just one event handler at the body level and then we can check the actual source of the bubbled event against a collection of elements that match your criteria.

See inline comments for more:

// Set the event listener at the <body> and wait for other
// events to bubble up to it.
document.body.addEventListener("click", function(evt){
  // Get an array of all the <a> elements that are descendants of <div> elements
  let matches = Array.prototype.slice.call(document.querySelectorAll("div a"));
  
  // Test to see if array contains the one that was clicked
  if(matches.includes(evt.target)){
    console.log("You clicked an <a> that is a descendant of a <div>!");
  }
});
<div>
  <section>
    <a>first</a>
    <a>second</a>
  </section>
</div>

<section>
  <a>third</a>
  <a>fourth</a>
</section>

<section>
  <div>
    <a>fifth</a>
    <a>sixth</a>
  </div>
</section>

Upvotes: 0

Related Questions