207

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...

isherwood
  • 58,414
  • 16
  • 114
  • 157
thomas
  • 2,071
  • 2
  • 13
  • 3
  • 9
    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. – rlemon Mar 14 '12 at 21:22
  • 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. – JasonXA Jun 26 '15 at 19:12

10 Answers10

181

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 ));
isherwood
  • 58,414
  • 16
  • 114
  • 157
user113716
  • 318,772
  • 63
  • 451
  • 440
  • Upvote, third option here is important part of understanding JS binding/unbinding – SW4 May 19 '15 at 14:18
  • would `myClick = function(event){...}` be considered a named function too? – Daniel Möller Jul 28 '15 at 18:35
  • I wonder If I could do: `myClick = function....`, then `another = myClick` and finally `removeEventListener('click', another)` ?? – Daniel Möller Jul 28 '15 at 19:02
  • @Daniel since `myClick(0)` returns a function, of course you can – alebianco Dec 20 '16 at 09:15
  • 1
    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](https://stackoverflow.com/a/73087167/740553) these days. – Mike 'Pomax' Kamermans Jul 27 '22 at 15:33
98
   canvas.addEventListener('click', function(event) {
      click++;
      if(click == 50) {
          this.removeEventListener('click',arguments.callee,false);
      }

Should do it.

edeverett
  • 8,012
  • 33
  • 28
  • 16
    This is cool! Doc on `arguments.callee` for interested parties: https://developer.mozilla.org/en/JavaScript/Reference/Functions_and_function_scope/arguments/callee – Ender Dec 09 '10 at 19:48
  • 12
    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!) – Dai May 30 '20 at 02:18
93

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/.

Tama
  • 1,625
  • 15
  • 11
13

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);
user113716
  • 318,772
  • 63
  • 451
  • 440
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
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;
};
};
Vinyl Windows
  • 503
  • 1
  • 7
  • 19
6

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 tell the JS engine to remove an event listener by just calling abort() instead of having to bother with removeEventListener:

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

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

(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. No keeping a reference to the handling function, no making sure we call removeEventListener with the exact same properties as we called addEventListener: we just cancel the listener.

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
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 :)

youssman
  • 1,514
  • 1
  • 17
  • 21
4

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.

Ender
  • 14,995
  • 8
  • 36
  • 51
-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();
-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>
user3870075
  • 141
  • 1
  • 3
  • 10