Skip to content

Instantly share code, notes, and snippets.

@bradwestfall
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bradwestfall/c87fb32047247eac899b to your computer and use it in GitHub Desktop.
Save bradwestfall/c87fb32047247eac899b to your computer and use it in GitHub Desktop.
jQuery Event Delegation (Live Binding)

Event Binding in jQuery

In jQuery, event binding can be a confusing topic at first. Especially when we attempt to do Delegated Events (or live binding , binding to elements that don't exist on the screen yet)

But first, let's clear up just a few things regarding normal event binding...

.click vs .on('click')

jQuery provides specific methods such as .click() or .mouseover() which can be used in this way

$('a').click(function() {

});

It's very important to understand that at the time we run any jQuery code, the $([subject matter]) needs to exist in order for the jQuery to work. So in the above case, this code would work for all anchors that exist on the page now, but if new ones were to come into existence, they would not be bound to the click event. It doesn't retroactively work that way.

Another way to bind events to DOM is with the .on() method. Notice the slight syntax difference. In this case the method .on() takes two arguments, the first is a string for the name of the event, and the second is the callback function. When the .on() method is used this way, it will work exactly like the .click() method from before. In fact the .click() method in jQuery maps directly to the .on('click') if you were to open the source code.

$('a').on('click', function() {

});

I won't go into why jQuery has these two ways of doing the same thing, although the .on() method does have some more abilities if we use it in a slightly different way...

Event Bubbling

But before we go any further, we need to talk about what is called "Event Bubbling". Event Bubbling means that anytime an event happens to a DOM element, that same event will also happen to all of that element's decendants (parents). So imagine an anchor that's deeply nested in other DOM. When the anchor gets clicked it will fire the event for that anchor and then it will fire the same click event for the anchor's parent. Then the click event will happen for the parent's parent. The click event, like ripples in watter will happen for every parent all the way to the body element and then the document node itself. Now just because every parent element gets it's click event fired doesn't mean that functions will get called for each one though. Only the elements that you have bound events to will get called.

Another important term that will come up soon is the term "Target". In Event Bubbling, the Target is the element that first received the event. So in the case of our example, the anchor that was clicked is the target. When the parents all get their click event fired soon after, they are not the target, only the anchor.

Event Delegation (Live Binding)

So hopefully that explanation of Event Bubbling made sence because we are going to use that concept to fix our problem - remember we want to bind to elements that don't exist yet? So let's create a scenario: Say we have a button that exists in a <nav> container. Even though the <nav> container exists all the time, the button won't exist in the DOM until later. We could wait until that button exists later and then at that time bind events to it, or we can do what's called Event Delegation (sometimes also referred to as Live Binding).

The Event Delegation way is sometimes preferred because it allows us to bind events to DOM elements that don't exist yet and we can do all our event binding when the page first starts.

As you saw moments ago, the .on() method takes two arguments: a string for the name of the event and a callback function. Essentially it works like this:

$([target]).on('click', [callback]);

But it also can work this way with three arguments:

$([parent]).on('click', [target], [callback]);

Notice that the target element (the actual element that get's clicked) is moved to be the second argument in the .on() method and thus we make the callback the third argument. Then notice how we've bound the event to a parent of our target. Here is some real code

$('nav').on('click', 'button', function() {

});

In this case, we are actually binding to the <nav> tag's click event. When the button gets clicked, the button will be the target but based on the Event Bubbling rules the nav's click event will happen soon after the target. So in a way you have to think of it as being an event that happens to both the <nav> and the <button>. But the cool part is when jQuery sees three arguments in the .on() method, it will check to see if the target of the event matches that second argument. In other words, the order of what happens is as follows:

  • A click occurs on the <button>
  • We didn't bind any events to the button so nothing happens yet
  • The event bubbles up to the <nav>
  • We have an event bound to the <nav> so run this .on() method
  • The .on() method checks to see if the target matches this selector: 'button'
  • It does! so the callback is called

Here is the REALLY IMPORTANT PART! The target doesn't have to exist in the DOM yet in order for this to work. So in our case remember the <nav> always exists - therefore it makes a good candidate to bind our event to. But the <button>s don't exist yet. That's okay because every time the <nav> gets it's event fired, it's going to look to see if the target is a <button> and if it is, the callback fires, if not it wont.

It's also important to remember that we can use this type of Event Delegation on any of the parents of the <button>. Sometimes you'll see documentation or examples online do things like this:

$(document).on('click', 'button', function() {

});

This works just like with the <nav> except we're just waiting for the event to bubble all the way up to the document. It's just another way to do the same thing. For performance reasons we probably don't want to have 100s of events bound to the document so I'm more of a fan of binding to other parent elements if I can, such as the <nav> in this case.

For the officialy documentation on this Click Here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment