Home > Net >  Event delegation does not capture all inner elements
Event delegation does not capture all inner elements

Time:08-22

I am using event delegation on my project but for some reason it does not works as expected.

It may seem like a duplicated question but searching for days I have not found the solution so it is not as clear, even in a course I am taking at UDEMY this is not addressed.

The html structure is like this:

<div >
 
  
  <a  id='. $row['unique_id'] .'>
    <div >
       <img src="php/images/'. $row['img'] .'" alt="">
       <div >                                       
          <span>'. $row['fname']. " " . $row['lname'] .'</span>                
          <p>'. $you . $msg .'</p>  </div>                     
        </div>
        <div ><i ></i>
    </div>
   </a>
 
 
</div>

The vars with the dollar sign are php variables and everything inside "users-list" <div> is added dynamically to the DOM (that part works well).

The problem comes when handling the event listener in javascript as follows:

const ulist = document.querySelector(".users-list");
ulist.addEventListener("click", (e) => {
  e.preventDefault();
  console.log(e.target);
  if (e.target.classList.contains("useruid")) {
    console.log(e.target.id);
  }
});

I need to get the id number inside the element to use it in another part of the program but it will only be captured if I click on the outer boundaries of the box and most of the time only the <span> and the <p> elements are the ones that will capture the click.

What do I'm missing here, isn't the click suppose to bubble up all the way up passing through the <a> element not matter where I click in that box?

I've searched on other questions here and everywhere online for days but can't find a clear solution. Maybe my approach is incorrect, I don't know really.

Adding additional clarification

using this has the same problem:

if (e.target.matches("a.useruid")) {
    console.log(e.target.id);
  }

CodePudding user response:

What do I'm missing here, isn't the click suppose to bubble up all the way to the <a> element not matter where I click in that box?

No. It bubbles up to <div > because that is where the event listener is bound.

The target is the element that triggered the event.

You need to change your logic from does the clicked element have the class to does the clicked element or one of its ancestors have the class.

You can do that with closest.

const ulist = document.querySelector(".users-list");
ulist.addEventListener("click", (e) => {
  e.preventDefault();
  const anchor = e.target.closest(".useruid");
  console.log(e.target);
  console.log(anchor)
  if (anchor) {
    console.log(anchor.id);
  }
});
<div >
 <a  id='one'>
    <div >
      <img src="//placekitten.com/100/100" alt="">
      <div >
        <span>foo</span>
        <p>bar</p>
      </div>
    </div>
  </a>
</div>

CodePudding user response:

The target will be the most nested element that has been clicked, So, it maybe a child element to .useruid element.

I think you need to use closest

const ulist = document.querySelector(".users-list");
ulist.addEventListener("click", (e) => {
  e.preventDefault();
  console.log(e.target);
  if (e.target.closest(".useruid")) {
    console.log(e.target.id);
  }
});

CodePudding user response:

e.target represents the element event was called upon. If you click on span, your e.target is that span.

To solve the problem, you first have to check if the event was called on anchor tag.

const myTarget = e.target.matches("a")? e.target : e.target.closest("a") 
  • Related