How can I remove a JavaScript event listener?
Asked Answered
A

10

217

I'm trying to remove an event listener inside of a listener definition:

canvas.addEventListener('click', function(event) {
    click++;
    if(click == 50) {
        // remove this event listener here!
    }
// More code here ...

How could I do that? this = event...

Aoristic answered 9/12, 2010 at 19:33 Comment(2)
trivial but for the future references if(click == 50) { should be if( click === 50 ) or if( click >= 50 ) - they will not change the output, but for sanity reasons these checks make more sense.Optometry
Good question... how do I remove it if I don't have access to the content? I want to remove popups for onclick on buttons using greasemonkey for other sites, but unless I can reference the function by name, I don't seem to find a way to remove it.Episcopacy
L
192

You need to use named functions.

Also, the click variable needs to be outside the handler to increment.

var click_count = 0;

function myClick(event) {
    click_count++;
    if(click_count == 50) {
       // to remove
       canvas.removeEventListener('click', myClick);
    }
}

// to add
canvas.addEventListener('click', myClick);

You could close around the click_counter variable like this:

var myClick = (function( click_count ) {
    var handler = function(event) {
        click_count++;
        if(click_count == 50) {
           // to remove
           canvas.removeEventListener('click', handler);
        }
    };
    return handler;
})( 0 );

// to add
canvas.addEventListener('click', myClick);

This way you can increment the counter across several elements.


If you don't want that, and want each one to have its own counter, then do this:

var myClick = function( click_count ) {
    var handler = function(event) {
        click_count++;
        if(click_count == 50) {
           // to remove
           canvas.removeEventListener('click', handler);
        }
    };
    return handler;
};

// to add
canvas.addEventListener('click', myClick( 0 ));
Lipo answered 9/12, 2010 at 19:41 Comment(5)
Upvote, third option here is important part of understanding JS binding/unbindingMistranslate
would myClick = function(event){...} be considered a named function too?Barkeeper
I wonder If I could do: myClick = function...., then another = myClick and finally removeEventListener('click', another) ??Barkeeper
@Daniel since myClick(0) returns a function, of course you canThirlage
Note that while true back in 2010, this hasn't been true since late 2020 when control signals were introduced for events. You no longer need named functions, or even removeEventListener for that matter: you can just abort an event directly these days.Porfirioporgy
R
101
   canvas.addEventListener('click', function(event) {
      click++;
      if(click == 50) {
          this.removeEventListener('click',arguments.callee,false);
      }

Should do it.

Rosenkrantz answered 9/12, 2010 at 19:43 Comment(2)
This is cool! Doc on arguments.callee for interested parties: developer.mozilla.org/en/JavaScript/Reference/…Conflux
Unfortunately this doesn't work with ECMAScript 5 (2009) or later, from the MDN link: "The 5th edition of ECMAScript (ES5) forbids use of arguments.callee() in strict mode. Avoid using arguments.callee() by either giving function expressions a name or use a function declaration where a function must call itself." (though it's using callee() instead of callee, it's still removed, boo!)Duggan
O
99

You could use a named function expression (in this case the function is named abc), like so:

let click = 0;
canvas.addEventListener('click', function abc(event) {
    click++;
    if (click >= 50) {
        // remove event listener function `abc`
        canvas.removeEventListener('click', abc);
    }
    // More code here ...
}

Quick and dirty working example: http://jsfiddle.net/8qvdmLz5/2/.

More information about named function expressions: http://kangax.github.io/nfe/.

Overactive answered 6/1, 2014 at 21:44 Comment(0)
S
15

If @Cybernate's solution doesn't work, try breaking the trigger off in to it's own function so you can reference it.

clickHandler = function(event){
  if (click++ == 49)
    canvas.removeEventListener('click',clickHandler);
}
canvas.addEventListener('click',clickHandler);
Spicebush answered 9/12, 2010 at 19:40 Comment(0)
A
9

It looks like no one's covered the part of the current JavaScript DOM specification that gives you a mechanism to remove your event listener without using removeEventListener. If we look at https://dom.spec.whatwg.org/#concept-event-listener we see that there are a number of properties that can be passed to control event listening:

{
  type (a string)
  callback (null or an EventListener object)
  capture (a boolean, initially false)
  passive (a boolean, initially false)
  once (a boolean, initially false)
  signal (null or an AbortSignal object)
  removed (a boolean for bookkeeping purposes, initially false) 
}

Now, there's a lot of useful properties in that list, but for the purposes of removing an event listener it's the signal property that we want to make use of (which was added to the DOM level 3 in late 2020), because it lets us send an abort signal and have JS do the rest without needing to save our event handling function somewhere and then calling removeEventListener with the exact same combination of arguments as we registered the listener:

const controller = (new AbortController()).signal;

canvas.addEventListener('click', () => {
  click++;
  if (click === 50) {
    controller.abort();
  } else {
    doSomethingWith(click);
  }
}, {
  // register our 
  signal: controller
});

(Note that this does not use the useCapture flag, because the useCapture flag is essentially completely useless)

And done: the JS engine will abort and clean up our event listener once controller.abort() gets called, without having to call removeEventListener with the exact same function and properties as we called addEventListener: just cancel the listener.

Ancell answered 23/7, 2022 at 0:12 Comment(0)
S
8
element.querySelector('.addDoor').onEvent('click', function (e) { });
element.querySelector('.addDoor').removeListeners();


HTMLElement.prototype.onEvent = function (eventType, callBack, useCapture) {
this.addEventListener(eventType, callBack, useCapture);
if (!this.myListeners) {
    this.myListeners = [];
};
this.myListeners.push({ eType: eventType, callBack: callBack });
return this;
};


HTMLElement.prototype.removeListeners = function () {
if (this.myListeners) {
    for (var i = 0; i < this.myListeners.length; i++) {
        this.removeEventListener(this.myListeners[i].eType, this.myListeners[i].callBack);
    };
   delete this.myListeners;
};
};
Sherrilsherrill answered 30/5, 2012 at 19:53 Comment(0)
C
6

I think you may need to define the handler function ahead of time, like so:

var myHandler = function(event) {
    click++; 
    if(click == 50) { 
        this.removeEventListener('click', myHandler);
    } 
}
canvas.addEventListener('click', myHandler);

This will allow you to remove the handler by name from within itself.

Conflux answered 9/12, 2010 at 19:42 Comment(0)
B
4

If someone uses jquery, he can do it like this :

var click_count = 0;
$( "canvas" ).bind( "click", function( event ) {
    //do whatever you want
    click_count++;
    if ( click_count == 50 ) {
        //remove the event
        $( this ).unbind( event );
    }
});

Hope that it can help someone. Note that the answer given by @user113716 work nicely :)

Birgitbirgitta answered 8/8, 2014 at 9:57 Comment(0)
T
-2

A way to achieve that is use jquery, so you can use:

canvas.click(yourfunction);

then you can detach all event listener with:

canvas.off();
Tadzhik answered 15/8, 2022 at 14:38 Comment(4)
jQuery is obsolete, and anyway the OP didn't ask about the jQuery framework anyway.Paraphrastic
"jQuery is obsolete" [citation needed]Newsreel
@AndreaLazzarotto Easy: youmightnotneedjquery.com ES6 has made jQuery unnecessary. The only thing jQuery really going for it now is a ready-made plugin environment... but reliance on untrusted 3rd party developer code in any production environment is a foolish risk anyway, especially when that plugin may be unsupported by the time you find it. Lets not forget: jQuery IS JavaScript, so it's just bloat you can ALWAYS do ANYTHING jQuery does in vanilla JS. It just so happens that modern ECMAScript is basically as easy as jQuery now.Paraphrastic
@Paraphrastic You are right to an extent. JQuery has always been something that can be done in JS obviously. That's not something you can put against anything actually. Having an API maintained by others as opposed to maintained by you is pretty much what's going for JQuery and any other JS library. For a reason its till 78% in use in top 1 million sites. Still I would love to have something better than both vanilla and JQuery and that's not React.Facultative
C
-7

Try this, it worked for me.

<button id="btn">Click</button>
<script>
 console.log(btn)
 let f;
 btn.addEventListener('click', f=function(event) {
 console.log('Click')
 console.log(f)
 this.removeEventListener('click',f)
 console.log('Event removed')
})  
</script>
Chromoprotein answered 5/11, 2016 at 13:47 Comment(1)
Not really a good practice to help people with however…Lithiasis

© 2022 - 2024 — McMap. All rights reserved.