Remove event listener in JavaScript - javascript

I add an event listener to an element:
/* sitepoint.com/javascript-this-event-handlers */
function AttachEvent(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
}else{
element.attachEvent("on"+type, handler);
}
}
window.addEventListener("load", function() {
var els = getElementsByClassName('name', 'img');
var elsnum = els.length;
if(elsnum) //found
{
var i = 0;
for(i=0; i < elsnum; i++)
{
var the_els = els[i];
AttachEvent(the_els, "click", myfunction);
}
}
}, false);
Later in myfunction, I want to remove the handler again, to prevent duplicate clicks:
function myfunction(e) {
e = e || window.event;
var target = e.target || e.srcElement;
//more code
//...
//remove click handler
target.removeEventListener('click', e, false);
//more code
//...
}
The event listener is not being removed, though. When I click on one of the elements, the code of myfunction is executed again. How can I remove the event listener to prevent the clicked element from being clicked again?
PS: I do not use jQuery.

I believe you're almost there, but you have to pass the listener to removeEventListener, not the event itself. So try:
target.removeEventListener('click', myFunction, false);

Use element.removeEventListener(type, listener, useCapture)
Remember to use that on the same element, and give it the exact same parameters as you did for adding.
One excellent way to code this would be to make a function that stores the listener details in a variable, mimicking how setTimeout() works for instance, and adding that to the element prototype. Here's an example function.
HTMLElement.prototype.eventListener=
function(type, func, capture){
if(typeof arguments[0]=="object"&&(!arguments[0].nodeType)){
return this.removeEventListener.apply(this,arguments[0]);
}
this.addEventListener(type, func, capture);
return arguments;
}
That will add a method to all HTML nodes that already can accept event listners, and allow you to do this.
var a=element.eventListener('click', myFunction, false); //to add
element.eventListener(a); //to remove

http://www.quirksmode.org/js/events_advanced.html
To remove an event handler, use the removeEventListener() method.
Also see http://help.dottoro.com/ljahxbsx.php
object.removeEventListener (eventName, listener, useCapture);
listener - Required. Reference to the event handler function to remove. You need to pass what listener you want to remove.

Related

How to run event listener only once? [duplicate]

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...
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);
EDIT: 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 ));
EDIT: I had forgotten to name the handler being returned in the last two versions. Fixed.
canvas.addEventListener('click', function(event) {
click++;
if(click == 50) {
this.removeEventListener('click',arguments.callee,false);
}
Should do it.
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/.
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);
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;
};
};
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.
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.
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 :)
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();
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>

How to cancel next event calls?

I have an event "pointerdown" but I want it to cancel the event call when a certain condition is met in one of the callbacks. So, all the next callbacks should not be called.
I have tried evt.preventDefault(); but that does not work, I have also tried evt.stopPropagation(); but that does not work.
const pointer = getMousePos(evt);
if (inBounds(pointer)) {
evt.preventDefault();
evt.stopPropagation();
}
The inBounds function returns true as expected, but the next callbacks of the event are still called. This event is added first, before the other events I wish to cancel but they are not.
If your listeners are attached on the same element, you will need to use stopImmediatePropagation() instead of stopPropagation()
The stopImmediatePropagation() method of the Event interface prevents other listeners of the same event from being called.
If several listeners are attached to the same element for the same event type, they are called in the order in which they were added. If stopImmediatePropagation() is invoked during one such call, no remaining listeners will be called.
https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation
You can also find a little description of the difference between both methods here:
stopPropagation vs. stopImmediatePropagation
Here a little demonstration of how you can use it. In this case, the second listener will never be called when the counter is a even number.
let counter = 0
const button = document.getElementById('TheButton')
button.addEventListener('click', e => {
counter++
console.log(`first listener: ${counter}`)
if (counter % 2 === 0) e.stopImmediatePropagation()
})
button.addEventListener('click', e => {
console.log(`second listener: ${counter}`)
})
<button id="TheButton">
OK
</button>
Use a global variable that you toggle to indicate whether the other event code should run.
let doBFunction = true;
element.addEventListener("pointerdown", function(evt) {
const pointer = getMousePos(evt);
if (inBounds(pointer)) {
doBFunction = false;
} else {
doBFunction = true;
}
// rest of code
});
element.addEventListner("pointerdown", function(evt) {
if (!doBfunction) {
return;
}
// rest of code
});

Remove keydown event listener [duplicate]

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...
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);
EDIT: 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 ));
EDIT: I had forgotten to name the handler being returned in the last two versions. Fixed.
canvas.addEventListener('click', function(event) {
click++;
if(click == 50) {
this.removeEventListener('click',arguments.callee,false);
}
Should do it.
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/.
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);
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;
};
};
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.
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.
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 :)
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();
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>

Remove specific set of event listeners from an HTML element using JavaScript

I want to remove only the mouseup event listners from a selected HTML element.
I used the below code but it will remove all listners.
var old_element = divs[d];
var new_element = old_element.cloneNode(true);
old_element.parentNode.replaceChild(new_element, old_element);
this is how i attach event listners.
var divs = document.getElementsByTagName('body');// to enhance the preformance
for(var d in divs) {
try{
if (divs[d].addEventListener) {
divs[d].addEventListener('mouseup',callHighlight);
} else {
divs[d].attachEvent('mouseup', callHighlight);
}
}catch(err){
//alert(err.message);
}
}
You should use removeEventListener instead of replacechild which will obviously remove all events.
old_element.removeEventListener('mouseup', handler);
When cloning an element, listeners added using addEventListener or by direct property assignment (element.onclick = fn;) are removed, but in–line listeners and those added using IE's attachEvent are not.
In your scenario where listeners are added by reference and also possibly using attachEvent, you are best to remove them using removeEventListener and detachEvent. So you might like to create add and remove functions like:
function addEvent(element, event, fn) {
if (element.addEventListener) {
element.addEventListener(event, fn, false);
} else if (element.attachEvent) {
element.attachEvent('on' + event, fn);
}
}
function removeEvent(element, event, fn) {
if (element.removeEventListener) {
element.removeEventListener(event, fn);
} else if (element.detachEvent) {
element.detachEvent('on' + event, fn);
}
}
Note that there are some significant differences between addEventListener and attachEvent, the most important are that in the latter, this is not set to the element whose handler is calling the function and a reference to the event isn't passed as the first argument to the listener. So the listener function ends up looking like:
function foo(evt) {
evt = evt || window.event;
var target = evt.target || evt.srcElement;
...
}
There are ways around this, but they introduce more issues. Keep it simple if you can.
By default all event listeners are null, so simply just reset it. Problem is that all your mouseup events are registered to the body, so therefore you won't be able to drop the event without first stopping the event from bubbling to the body. You can solve that problem with, stopPropagation()
old_element.onmouseup = function (e) {
// event won't go up to the body tag
e.stopPropagation();
return null;
};
or
function kill (e) {
e.stopPropagation();
return null;
}
old_element.onmouseup = kill;
second_element.onmouseup = kill;
JSFIDDLE

How to get the id attribute of a dynamically-generated element?

How can I get the id attribute of a dynamically generated element when you don't know it's id? I am wanting to setup some eventListeners for about 2000 Checkbox's on a page.
I know I could call a function from within the element:
<input type="checkbox" id="{databaseResult.Value}" onclick="someFunction(this)" />
But I'm not allowed to use JavaScript, or references to it in my HTML. Pure JavaScript (or a language that compiles to it) is my only option.
The code I already have for some elements where I do know the id, is:
var tb = <HTMLInputElement>document.getElementById("tbox");
if(tb.addEventListener("", function (e) {
sayHello(tb.value);
}, false));
Put a single listener on an ancestor element, say the body, and listen for events on that, e.g.:
<body onclick="handleClick(event);" ...>
and the function is:
function handleClick(evt) {
var el = evt.target || evt.srcElement;
if (el && el.type == 'checkbox') {
alert(el.id);
}
}
Of course you can add the listener dynamically, I've used inline for convenience.
Edit
To attach the listener dynamically, use an addEvent function to cope with IE and W3C event models:
function addEvent(el, evt, fn) {
// W3C event model
if (el.addEventListener) {
el.addEventListener(evt, fn, false);
// IE event model
// Set this and pass event as first parameter
} else if (el.attachEvent) {
el.attachEvent('on' + evt, (function(el, fn) {
return function() {fn.call(el, window.event);};
})(el, fn)
);
}
// Prevent circular reference
el = null;
}
And call it as:
window.onload = function() {
addEvent(document.body, 'click', handleClick);
}

Categories