Javascript event delegation, handling parents of clicked elements?
Asked Answered
T

2

21

http://jsfiddle.net/walkerneo/QqkkA/

I've seen many questions here either asking about or being answered with event delegation in javascript, but I've yet to see, however, how to use event delegation for elements that aren't going to be the targets of the click event.

For example:

HTML:

<ul>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
    <li><div class="d"></div></li>
</ul>​

CSS:

ul{
    padding:20px;
}
li{
    margin-left:30px;
    margin-bottom:10px;
    border:1px solid black;

}
.d{
    padding:10px;
    background:gray;
}
​

What if I want to add a click event to handle the li elements when they're clicked? If I attach an event handler to the ul element, the divs will always be the target elements. Apart from checking every parent of the target element in a click function, how can I accomplish this?

edit:

I want to use event delegation instead of:

var lis = document.getElementsByTagName('li');
for(var i=0;i<lis.length;i++){
    lis[i].onclick = function(){};
}

But if I do:

document.getElementsByTagName('ul')[0].addEventListener('click',function(e){

    // e.target is going to be the div, not the li
    if(e.target.tagName=='LI'){

    } 
},false);

EDIT: I'm not interested in how to use Javascript libraries for this, I'm interested in how they do it and how it can be done with pure js.

Threnody answered 28/3, 2012 at 19:46 Comment(3)
Actually confused about your question, didn't understand what do you want to achieve.Character
I always get screwed up on this... this link may help: quirksmode.org/js/events_order.htmlKharkov
@Michal, It seemed inefficient, I was wondering if that was the only way.Threnody
E
22

Here's one way to solve it:

var list = document.getElementsByTagName('ul')[0]

list.addEventListener('click', function(e){
  var el = e.target
  // walk up the tree until we find a LI item
  while (el && el.tagName !== 'LI') {
     el = el.parentNode
  }
  console.log('item clicked', el)
}, false)

This is overly simplified, the loop will continue up the tree even past the UL element. See the implementation in rye/events for a more complete example.

The Element.matches, Node.contains and Node.compareDocumentPosition methods can help you implement this type of features.

Elouise answered 28/3, 2012 at 21:15 Comment(2)
I did some digging into jQuery, and this is what I found.Threnody
Thanks :) It's what I need.Tendinous
P
8

There is now a method on elements called closest, which does exactly this. It takes a CSS selector as parameter and finds the closest matching ancestor, which can be the element itself. All current versions of desktop browsers support it, but in general it is not ready for production use. The MDN page linked above contains a polyfill.

Pulpboard answered 16/5, 2017 at 16:51 Comment(1)
Perfect! That's exactly what I need. ThanksGeminius

© 2022 - 2024 — McMap. All rights reserved.