42

Can someone explain me why is there a difference in the order in which the event handlers are being executed depending on how they have been attached? In the example below I'm using the .on() and .addEventListener() methods to handle a specific event on different DOM elements.

jsfiddle: http://jsfiddle.net/etsS2/

I thought that in this particular example the order in which the event handlers are going to be executed will depend on the event-bubbling - so starting from the original event target and moving up to the document element.

document.getElementById('outer').addEventListener('mouseup', function (event) {
//$('#outer').on('mouseup', function (event) {
    alert('This alert should not show up!');
}, false);

If I uncomment the on(); version everything works as expected - is there a difference in how jQuery handles events contrary to plain JavaScript?

MonkeyCoder
  • 2,600
  • 2
  • 28
  • 30

2 Answers2

25

When you use .on() at the document level, you're waiting for the event to bubble all the way up to that point. The event handler for any intermediate container will already have been called.

Event "bubbling" is the process by which the browser looks for event handlers registered with parents of the element that was the actual original recipient of the event. It works upwards in the DOM tree. The document level is the last level checked. Thus, your handler registered with .on() won't run until that level is reached. In the meantime, the other event handler at the "outer" level is reached first and it is executed by the browser.

Thus, that return false; in the handler registered with .on() is pretty much useless, as would be a call to event.stopPropagation(). Beyond that, mixing native event handler registration with the work that a library like jQuery will do is probably a really bad idea unless you seriously know what you're doing.

There was a question asked almost exactly like this one just a little while ago today.

Community
  • 1
  • 1
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • `return false` also does `event.preventDefault()` as well as `event.stopPropagation()` in a jQuery event handler. – Jasper Jan 25 '12 at 00:04
  • The reason why I've created this structure is due to the fact that the `a.link` element is add dynamically and somehow I need to prevent the `outer` div from handling that particular event - how can I achieve that? So basically you mean that this: $(document).on('mouseup', 'a.link' ...) is equal to this: $('a.link').live('mouseup', ...)? – MonkeyCoder Jan 25 '12 at 00:05
  • 1
    Yes - the only way a mechanism like `.live()`, `.delegate()`, or the new `.on()` can work is via bubbling, and the bubbling works from the inside out. You could instead make sure that event listeners for dynamically-added elements are bound directly to the elements when they're added to the DOM. – Pointy Jan 25 '12 at 00:10
  • Thanks! It makes sense why they deprecated the `live()` method - originally I thought that it is possible to achieve something similar without explicitly attaching a listener to a dynamically added element – MonkeyCoder Jan 25 '12 at 00:35
  • 1
    @Pointy: I know this answer is a few month old but +1 for explaining the differences and why it could lead to issues mixing native with jQuery even binding. I never realised that there was such a difference as I nver mixed them myself. Thank you. – Nope Apr 11 '13 at 08:48
13

Look at the addEventListener version:

document.getElementById('outer').addEventListener('mouseup', function (event) {
    alert('This alert should not show up!');
}, false);

That works fine because the third argument is useCapture, which specifies whether or not the capture phase of the event should be used.

When you switch to the jQuery version:

$('#outer').on('mouseup', function (event) {
    alert('This alert should not show up!');
}, false);

I think what is happening is the third argument simply overrides your event handler function and causes the event handler to do nothing but return false; which is clearly not what is meant to happen.

From the jQuery docs (emphasis added):

A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false.

Remove the false argument and the jQuery version will work correctly too:

$('#outer').on('mouseup', function (event) {
    alert('This alert should not show up!');
});

Note that the alert should show up, so the addEventListener approach is working correctly. See @Pointy's answer for why that is.

James Allardice
  • 164,175
  • 21
  • 332
  • 312