7

I'm trying to wean myself off jQuery (my heart is in the right place, no?), and I'm having trouble getting to what would be the equivalent of the :not() selector.

I have document.body.addEventListener("mousewheel", scrollTriggered), which I want to fire on scroll of anything but a specific div (in the fiddle, #something). I've tried integrating event.target, to no avail.

Any help greatly appreciated. See JSFiddle

emsoff
  • 1,585
  • 2
  • 11
  • 16

4 Answers4

13

The easiest way is probably to set an addEventListener with the third argument to false that does the action, and then have another addEventListener on the element you want to exclude, with a third argument true, which will cancel the event from propagating to the other event listener. The third argument is a little complicated, but the important part is that if it's set to true, that listener will fire before any false handlers. As @FelixKling said, you actually don't need it to be true here, but it's good practice to do it whenever you need a handler to fire before another one, because sometimes it IS needed. Here's a jsfiddle example: http://jsfiddle.net/markasoftware/sBg3a/2/

document.body.addEventListener("mousewheel", scrollTriggered,false);

function scrollTriggered() {
    console.log('hi');
}

document.getElementById('something').addEventListener('mousewheel',function(e) {
    e.stopPropagation();
}, true);

Although @FelixKling's answer works, I personally think this is more elegant and generally use things like this instead of the other way. I just like how you can have the main event listener just have the listener code, and all the stuff that cancels the event from propagating can be completely separate, making it more unobstrusive

markasoftware
  • 12,292
  • 8
  • 41
  • 69
  • Good idea, but I don't think it's necessary to bind the handler in the capturing phase, you can also bind it in the bubbling phase. – Felix Kling Jun 11 '14 at 23:55
  • yeah, i guess, now that I think about it. I'm just used to using the capturing phase whenever i want a handler to fire before another one, just for good practice – markasoftware Jun 11 '14 at 23:56
13

You can check whether the event originated from within the element you want to avoid. To do that, you have to traverse up the DOM tree from target and compare each Node's id attribute, or use Node.contains (check the compatibility section first though):

var ignore = document.getElementById('something');

function scrollTriggered(event) {
    var target = event.target;
    if (target === ignore || ignore.contains(target)) {
        return;
    }
    // do other stuff
}

DEMO


That said, Markasoftware's answer is even better, since it prevents the event in the first place.

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
3

You can check the target element inside your event handler and if that target element has id something return false;

something like this:

function scrollTriggered (event) {
    if (event.target.id === "something") {
      // don't do anything
       return;
    } else {
       // do something  
    }
 }
Cute_Ninja
  • 4,742
  • 4
  • 39
  • 63
  • doesn't necessarily work, as it might bubble from an element inside of the "something" element and make this not work. @FelixKling's answer is probably a better idea – markasoftware Jun 11 '14 at 23:54
0

You will can use next example code with EcmaScript 6:

function scrollTriggered(event) {
    var target = event.target;
    if (target.outerHTML.includes('something')) { 
        return;
    }
    // do other stuff
}

We extract string from html element and try found in it something. This will work if you located inside necessary element which need ignore.

Paul Alexeev
  • 172
  • 1
  • 11