Reputation: 2241
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...
Upvotes: 224
Views: 409824
Reputation: 1
Remember, you must give every function a name because the name serves as the function's identifier.
If you do not assign a name to a function, it cannot be removed from a JavaScript event listener.
Example of a named function:
function closePop(event =new Event('click') ) {}
Example of an arrow function:
const closePop=(event =new Event('click'))=>{};
Now, if you want to remove an event listener:
cancelBtn.addEventListener('click', function closePop(event =new Event('click') ) {
cancelBtn.removeEventListener('click', closePop);
})
For an arrow function:
let f=()=>{
cancelBtn.removeEventListener('click', f);
};
cancelBtn.addEventListener('click',f )
Upvotes: -1
Reputation: 351
Signals is a new way to remove an event listener without reference to the callback function or the exact arguments used when registering it.
You'll need a signal object passed to addEventListener
:
const controller = new AbortController();
randomElement.addEventListener('click', randomCallback, {'signal':controller.signal});
Once that's done, you can use the AbortController
's abort
method to send the abort signal:
controller.abort();
All event listeners hooked up to that controller will be canceled with a single method call. The effect is identical to using removeEventListener
.
Many other answers on this page demonstrate how removeEventListener
can be inflexible. Signals opens up the door to canceling anonymous and arrow function-based event listeners without currying or otherwise storing a reference to the callback.
Upvotes: 1
Reputation: 53683
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();
canvas.addEventListener('click', () => {
click++;
if (click === 50) {
// Cancel and clean up the event using our controller:
controller.abort();
} else {
doSomethingWith(click);
}
}, {
// Tie our controller to this event binding:
signal: controller.signal
});
(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.
And of course, the value here is in the fact that we can use a single controller to abort multiple events simultaneously, so we can clean up some UI's touchstart
, touchend
, mouseenter
, mouseleave
, click
, focus
, blur
, and window scroll, all with a single call to .abort()
. No tracking event handlers, just have a reference to that single controller tied to your UI component, and set up the event handling to listen for its signal when it gets removed from the DOM.
Upvotes: 13
Reputation: 322582
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 ));
Upvotes: 199
Reputation: 13
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();
Upvotes: -3
Reputation: 1715
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/.
Upvotes: 102
Reputation: 141
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>
Upvotes: -7
Reputation: 1524
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 :)
Upvotes: 4
Reputation: 503
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;
};
};
Upvotes: 8
Reputation: 15221
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.
Upvotes: 6
Reputation: 8218
canvas.addEventListener('click', function(event) {
click++;
if(click == 50) {
this.removeEventListener('click',arguments.callee,false);
}
Should do it.
Upvotes: 102
Reputation: 101614
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);
Upvotes: 16