Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delegated events don't work in combination with :not() selector

I want to do something on all clicks except on a certain element.

I've created a very simple example which demonstrates the issue: http://jsfiddle.net/nhe6wk77/.

My code:

$('body').on('click', ':not(a)', function () {
    // do stuff
});

I'd expect all click to on <a> to be ignored, but this is not the case.

Am I doing something wrong or is this a bug on jQuery's side?

like image 211
Daniel Apt Avatar asked Mar 17 '15 18:03

Daniel Apt


2 Answers

There's a lot going on in that code that's not obvious. Most importantly, the click event is actually attached to the body element. Since that element isn't an anchor, you'll always get the alert. (Event delegation works because the click event bubbles up from the a through all its ancestors, including body, until it reaches document.)

What you want to do is check the event.target. That will tell you the element that was actually clicked on, but the actual click event is still bound to the body element:

$('body').on('click', function (e) { // e = event object
    if ($(e.target).is(':not(a)')) {
        alert('got a click');
    }
});

http://jsfiddle.net/y3kx19z7/

like image 106
Blazemonger Avatar answered Oct 11 '22 21:10

Blazemonger


No this is not a bug but rather intended behaviour.

The event bubbles all the way up. By clicking the a node, you are still triggering it's parents event from the div node.

Read more about event bubbling in the W3C DOM Specification. Just search for "bubble".

You need to stop the event propagation of the a nodes. i.e.:

$('body').on('click', ':not(a)', function () {
    // do something effectively
    alert('you should not see me when clicking a link');
});
$("a").click(function( event ) {
    // do nothing effectively, but stop event bubbling
    event.stopPropagation();
});

JSFiddle: http://jsfiddle.net/nhe6wk77/6/

like image 31
Kaii Avatar answered Oct 11 '22 21:10

Kaii