1
votes

I am trying to implement event delegation with the following code:

<html>
<head>
<script>
document.addEventListener('click', function(e){
    alert(e.target.className);
}, false);
</script>
</head>
<body>
<ul class="list">
    <li class="item">A</li>
    <li class="item">B</li>
    <li class="item">C</li>
    <li class="item">D</li>
</ul>
</body>
</html>

I want the event to bubble so that, when I click on an <li> item, an alert shows item, and then another alert shows list. But this code only gives the alert with item. How can I modify it so that the event bubbles?

5

5 Answers

1
votes

Event callback is only triggered once, but it does not mean the event does not bubble. The callback is only executed when the very element listens to the event.

If you really want the alert to be triggered all the way back to the ancestors, in your callback, add the alerts for the ancestors one by one. You dont have to add listeners to all the ancestors, which would cause consuming more memory.

1
votes

You need to add event for list to alert it. Event is captured by parent objects but there is no event bound to them so it doesn't alert. You need to add event for all objects to alert it.

1
votes

When you bind a click handler at the document object, you can't expect it to be invoked multiple times. It will be invoked only once (at the document object).

Btw the event does bubble up the DOM tree. If it didn't, it wouldn't reach the document object, and you wouldn't see any alert box.

So, the event fires at the LI element, and then bubbles all the way up to the document object, where the click handler is invoked.

Btw usually you don't delegate all the way up to the document object, but to the closest common ancestor. For example, if you want to handle clicks on the LI elements, you delegate to the UL element:

var list = document.getElementsByClassName( 'list' )[0];    

list.addEventListener( 'click', function ( e ) {
    var item = e.target;

    // handle item click
}, false );

Live demo: http://jsfiddle.net/rCVfq/

1
votes

I just released a small event delegation library to make it easier to do things like this. Check it out at http://craig.is/riding/gators

You can do

Gator(document).on('click', 'li', function() { alert('li clicked!'); });
Gator(document).on('click', 'ul', function() { alert('ul clicked!'); });

This will bind a single click handler to the document and will dispatch the events accordingly.

They will both fire when you click an li unless you stop propagation.

0
votes

You can use some looping method to invoke both alerts:

var list = document.getElementsByClassName('list')[0];
list.addEventListener("click", function (e) {
   var target = e.target;
   while (target !== list) {
      switch(target.nodeName) {
          case "LI": //alert('li clicked!')
          break;
          case "UL": //alert('ul clicked!')
          break;
      }
      target = target.parentNode;
   }
});