Event Delegation without jQuery

Today we’re going to listen to some buttons from a parent element, and we’re doing it without jQuery. We’re going to use vanilla JavaScript. I still love me some jQuery, of course, but we don’t gain a deeper understanding of JavaScript unless we dig into it a little bit and let go of our favorite tools.

Before I Digress…

I could easily derail myself here by getting up onto my soapbox and going on and on about efficiency, performance and other stuff. I’m going to try to save that for another post so I can get right down to business in this one. Before we go any further, here’s the completed fiddle. It’s commented pretty well, so I’m just going to go over the bit about delegation.

Our final product is going to be an input and a list. The input has a green button that adds the input’s contents to the list. Each item on the list is going to have its own button for removing itself. So it’s almost like a to-do list, but very basic.

First we cache our target elements to variables. We’re declaring the main ul tag, the main button that adds items, and the input that we’ll use to type in our new stuff. Once that’s done, we’ll need event listeners on the button and the list.

var stuffList = document.getElementById('stuff-list'),
  btnAdd = document.getElementById('btn-add'),
  listInput = document.getElementById('input-stuff');

btnAdd.addEventListener('click', plusHandler);
stuffList.addEventListener('click', minusHandler);

From here, we just write the event handler functions and we’re done. The main button handler is pretty clear in the fiddle, so I’d like to focus on the list handler. That’s the one we’re delegating. Have a look at this:

function minusHandler(event) {
  if(event.srcElement.tagName === 'BUTTON') {
    // Set to the parent of the thing you clicked.
    var targetNode = event.target.parentElement;

    // Tell the ul to remove the targeted list element.
    stuffList.removeChild( targetNode );
  }
}

What’s an event.target?

It’s just a few lines because I’m utilizing the event object. Seriously, try adding console.log(event) to some kind of handler and just drill down through that thing in the console. Or you can just do it in the fiddle, because I left a log statement in there.

There’s a bit of duplication in there, so you can get the identity of whatever was clicked from target or srcElement because they’re the same thing. You can get the identity of the thing that was actually clicked from either parentElement or parentNode, which are also the same thing.

In Bootstrap, this type of button has a span in it (which contains the glyphicon) and that can make things a bit weird with regard to who/what was clicked. To solve it, I went into the CSS and set the span’s to pointer-event:none. This means that the span is never clicked, so the event will just bubble up from the button. The button is the event target, and the parentElement is the list element that the button lives in. So our target node is always matched up to the button inside it. When we tell stuffList to remove targetNode, we’re telling the unordered list to get rid of the correct list element. The initial if statement makes sure that we don’t try any of this when the list element is clicked. We only want to respond to the button.

But what if we did use jQuery?

Well, our code would have looked like this:

$( "#stuff-list" ).on( "click", "button", function() {
  $(this).parent().remove();
});

It would have amounted to fewer lines, but we never would have learned anything about the event object. We would also be pulling in a rather large library just for a dinky little list adder-subtracter thingy. The lines we save in our little function would be gained back a hundredfold just by adding jQuery’s codebase to the mix.

Sometimes you really need jQuery, and once you’ve added it to a project then you should certainly take advantage of all it has to offer. But sometimes you’re going to make little things, and you’ll need to decide whether jQuery’s many fine qualities are worth the weight.