javascriptevent-handlingaddeventlistenerevent-bubblingevent-capturing

Event bubbling and capture on a root element with nested elements


I am trying to capture the id on each card from the root element. However, every time I click on a nested element I get empty string. However, I want the id from the wrapping card while listening on the root element cards. I want to handle both bubbling and capturing cases as this is part of a larger structure. I only want answers in vanilla js, and Javascript, no css please.

cards.addEventListener('click', evt => {
  if (evt.target !== evt.currentTarget) {
    var clickedItem = evt.target.id
    console.log(clickedItem);
  }
});
.card {
  /* Add shadows to create the "card" effect */
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
  transition: 0.3s;
}


/* On mouse-over, add a deeper shadow */

.card:hover {
  box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}


/* Add some padding inside the card container */

.container {
  padding: 2px 16px;
}
<div id="cards" style="margin: auto; width: 50%;">
  <div class="card" id="1234567"><img src="img_avatar.png">
    <div class="container">
      <h4>1st Note</h4>
      <p>Note Body</p>
    </div>
  </div>
  <div class="card" id="1234547"><img src="img_avatar.png">
    <div class="container">
      <h4>2nd Note</h4>
      <p>Note Body2</p>
    </div>
  </div>
  <div class="card" id="721680"><img src="img_avatar.png">
    <div class="container">
      <h4>3Note Body</h4>
      <p>Note Body3</p>
    </div>
  </div>
</div>


Solution

  • Yes, one listener is a good requirement. As it happens you only need to change the line where you get your target:

    cards.addEventListener('click', evt => {
      console.log( evt.target.closest( '.card' ).id );
    });
    

    Complete example:

    cards.addEventListener('click', evt => {
      alert( evt.target.closest( '.card' ).id );
    });
    .card {
      /* Add shadows to create the "card" effect */
      box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
      transition: 0.3s;
    }
    
    
    /* On mouse-over, add a deeper shadow */
    
    .card:hover {
      box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
    }
    
    
    /* Add some padding inside the card container */
    
    .container {
      padding: 2px 16px;
    }
    <div id="cards" style="margin: auto; width: 50%;">
      <div class="card" id="1234567"><img src="img_avatar.png">
        <div class="container">
          <h4>1st Note</h4>
          <p>Note Body</p>
        </div>
      </div>
      <div class="card" id="1234547"><img src="img_avatar.png">
        <div class="container">
          <h4>2nd Note</h4>
          <p>Note Body2</p>
        </div>
      </div>
      <div class="card" id="721680"><img src="img_avatar.png">
        <div class="container">
          <h4>3Note Body</h4>
          <p>Note Body3</p>
        </div>
      </div>
    </div>