Is there anyway to remove an event listener added like this:
element.addEventListener(event, function(){/* do work here */}, false);
Without replacing the element?
There is no way to cleanly remove an event handler unless you stored a reference to the event handler at creation.
I will generally add these to the main object on that page, then you can iterate and cleanly dispose of them when done with that object.
You could remove the event listener like this:
element.addEventListener("click", function clicked() {
element.removeEventListener("click", clicked, false);
}, false);
Anonymous bound event listeners
The easiest way to remove all event listeners for an element is to assign its outerHTML to itself. What this does is send a string representation of the HTML through the HTML parser and assign the parsed HTML to the element. Because no JavaScript is passed, there will be no bound event listeners.
document.getElementById('demo').addEventListener('click', function(){
alert('Clickrd');
this.outerHTML = this.outerHTML;
}, false);
<a id="demo" href="javascript:void(0)">Click Me</a>
Anonymous delegated event listeners
The one caveat is delegated event listeners, or event listeners on a parent element that watch for every event matching a set of criteria on its children. The only way to get past that is to alter the element to not meet the criteria of the delegated event listener.
document.body.addEventListener('click', function(e){
if(e.target.id === 'demo') {
alert('Clickrd');
e.target.id = 'omed';
}
}, false);
<a id="demo" href="javascript:void(0)">Click Me</a>
Old Question, but here is a solution.
Strictly speaking you can’t remove an anonymous event listener unless you store a reference to the function. Since the goal of using an anonymous function is presumably not to create a new variable, you could instead store the reference in the element itself:
element.addEventListener('click',element.fn=function fn() {
// Event Code
}, false);
Later, when you want to remove it, you can do the following:
element.removeEventListener('click',element.fn, false);
Remember, the third parameter (false) must have the same value as for adding the Event Listener.
However, the question itself begs another: why?
There are two reasons to use .addEventListener() rather than the simpler .onsomething() method:
First, it allows multiple event listeners to be added. This becomes a problem when it comes to removing them selectively: you will probably end up naming them. If you want to remove them all, then #tidy-giant’s outerHTML solution is excellent.
Second, you do have the option of choosing to capture rather than bubble the event.
If neither reason is important, you may well decide to use the simpler onsomething method.
Yes you can remove an anonymous event listener:
const controller = new AbortController();
document.addEventListener(
"click",
() => {
// do function stuff
},
{ signal: controller.signal }
);
You then remove the event listener like this:
controller.abort();
You may try to overwrite element.addEventListener and do whatever you want.Something like:
var orig = element.addEventListener;
element.addEventListener = function (type, listener) {
if (/dontwant/.test(listener.toSource())) { // listener has something i dont want
// do nothing
} else {
orig.apply(this, Array.prototype.slice.apply(arguments));
}
};
ps.: it is not recommended, but it will do the trick (haven't tested it)
Assigning event handlers with literal functions is tricky- not only is there no way to remove them, without cloning the node and replacing it with the clone- you also can inadvertantly assign the same handler multiple times, which can't happen if you use a reference to a handler. Two functions are always treated as two different objects, even if they are character identical.
Edit: As Manngo suggested per comment, you should use .off() instead of .unbind() as .unbind() is deprecated as of jQuery 3.0 and superseded since jQuery 1.7.
Even though this an old question and it does not mention jQuery I will post my answer here as it is the first result for the searchterm 'jquery remove anonymous event handler'.
You could try removing it using the .off() function.
$('#button1').click(function() {
alert('This is a test');
});
$('#btnRemoveListener').click(function() {
$('#button1').off('click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button1">Click me</button>
<hr/>
<button id="btnRemoveListener">Remove listener</button>
However this only works if you've added the listener using jQuery - not .addEventListener
Found this here.
If you're using jQuery try off method
$("element").off("event");
Jquery .off() method removes event handlers that were attached with .on()
With ECMAScript2015 (ES2015, ES6) language specification, it is possible to do with this nameAndSelfBind function that magically turns an anonymous callback into a named one and even binds its body to itself, allowing the event listener to remove itself from within as well as it to be removed from an outer scope (JSFiddle):
(function()
{
// an optional constant to store references to all named and bound functions:
const arrayOfFormerlyAnonymousFunctions = [],
removeEventListenerAfterDelay = 3000; // an auxiliary variable for setTimeout
// this function both names argument function and makes it self-aware,
// binding it to itself; useful e.g. for event listeners which then will be able
// self-remove from within an anonymous functions they use as callbacks:
function nameAndSelfBind(functionToNameAndSelfBind,
name = 'namedAndBoundFunction', // optional
outerScopeReference) // optional
{
const functionAsObject = {
[name]()
{
return binder(...arguments);
}
},
namedAndBoundFunction = functionAsObject[name];
// if no arbitrary-naming functionality is required, then the constants above are
// not needed, and the following function should be just "var namedAndBoundFunction = ":
var binder = function()
{
return functionToNameAndSelfBind.bind(namedAndBoundFunction, ...arguments)();
}
// this optional functionality allows to assign the function to a outer scope variable
// if can not be done otherwise; useful for example for the ability to remove event
// listeners from the outer scope:
if (typeof outerScopeReference !== 'undefined')
{
if (outerScopeReference instanceof Array)
{
outerScopeReference.push(namedAndBoundFunction);
}
else
{
outerScopeReference = namedAndBoundFunction;
}
}
return namedAndBoundFunction;
}
// removeEventListener callback can not remove the listener if the callback is an anonymous
// function, but thanks to the nameAndSelfBind function it is now possible; this listener
// removes itself right after the first time being triggered:
document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
{
e.target.removeEventListener('visibilitychange', this, false);
console.log('\nEvent listener 1 triggered:', e, '\nthis: ', this,
'\n\nremoveEventListener 1 was called; if "this" value was correct, "'
+ e.type + '"" event will not listened to any more');
}, undefined, arrayOfFormerlyAnonymousFunctions), false);
// to prove that deanonymized functions -- even when they have the same 'namedAndBoundFunction'
// name -- belong to different scopes and hence removing one does not mean removing another,
// a different event listener is added:
document.addEventListener("visibilitychange", nameAndSelfBind(function(e)
{
console.log('\nEvent listener 2 triggered:', e, '\nthis: ', this);
}, undefined, arrayOfFormerlyAnonymousFunctions), false);
// to check that arrayOfFormerlyAnonymousFunctions constant does keep a valid reference to
// formerly anonymous callback function of one of the event listeners, an attempt to remove
// it is made:
setTimeout(function(delay)
{
document.removeEventListener('visibilitychange',
arrayOfFormerlyAnonymousFunctions[arrayOfFormerlyAnonymousFunctions.length - 1],
false);
console.log('\nAfter ' + delay + 'ms, an event listener 2 was removed; if reference in '
+ 'arrayOfFormerlyAnonymousFunctions value was correct, the event will not '
+ 'be listened to any more', arrayOfFormerlyAnonymousFunctions);
}, removeEventListenerAfterDelay, removeEventListenerAfterDelay);
})();
//get Event
let obj = window; //for example
let eventStr= "blur"; //for example
let index= 0; //you can console.log(getEventListeners(obj)[eventStr]) and check index
let e = getEventListeners(obj)[eventStr][index];
//remove this event
obj .removeEventListener(eventStr,e.listener,e.useCapture);
THE END :)
i test in chrome 92, worked
How I used options parameter for my customEvent
options Optional
An object that specifies characteristics about the event listener. The available options are:
...
**once**
A boolean value indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
for my custom function that I created, it worked quite nicely.
const addItemOpenEventListener = (item, openItem) => {
document.addEventListener('order:open', ({detail}) => {
if(detail.id === item.id) {
openItem();
}
}, {once: true})
};
el.addItemOpenEventListener(item, () => dispatch(itemOpen)()));
checked my console, seems like it worked (any feedback appreciated!)
The following worked well enough for me. The code handles the case where another event triggers the listener's removal from the element. No need for function declarations beforehand.
myElem.addEventListener("click", myFunc = function() { /*do stuff*/ });
/*things happen*/
myElem.removeEventListener("click", myFunc);
I'm wondering which would be the proper way to deal with events which depend on the status of a variable.
Right now, I have a listener which it is only added if the option isTablet is set to true. (as if not, it breaks in old versions of IE). So it looks like this:
if(options.isTablet){
document.addEventListener('touchmove', function(e){
....
});
}
Now, I'm having troubles if I want to change the variable isTablet dynamically with a setter and It won't load the event touchmove.
$.fn.myPlugin.setIsTablet = function(value){
options.isTablet = value;
}
I guess the simple way is always adding the event and inside it deciding whether or not to execute the code:
document.addEventListener('touchmove', function(e){
if(options.isTablet){
....
}
});
But throws an error in IE 8:
Object doesn't support property or method 'addEventListener'
What would be the way of doing it?
Thanks.
Generally, I would always add the listener and check the condition inside. To avoid your error, since you're using jQuery, just use jQuery:
$(document).on('touchmove', function(e){
if(options.isTablet){
....
}
});
If you have a handler that is called very often, you could consider turning it off when not needed. Something like this:
function myHandler(e) { ... }
$.fn.myPlugin.setIsTablet = function(value){
options.isTablet = value;
if (value) {
$(document).off('touchmove').on('touchmove', myHandler);
} else {
$(document).off('touchmove');
}
}
Be careful not to bind the handler more than once (like if true is sent to setIsTablet more than once in a row). You could also use a flag instead of unbinding/binding like I've shown.
I have a situation where I need to use jQuery's $.fn.one() function for a click event, but I don't want it to apply to the next occurrence of the event (like it usually does), I want it to apply to the occurrence immediately after that, and then unbind itself (like .one() normally does).
The reason I don't want .one() to apply to the first occurrence is because I'm binding to the document from an event handler invoked earlier in the bubbling phase, so the first time it gets to document it'll be part of the same event. I want to know when the very next click event occurs.
Note: I do not want to use .stopPropagation() because it will potentially break other parts of my app.
Here are the two options I've come up with, though it seems like there must be a more elegant solution.
The double bind method:
$(document).one('click', function() {
$(document).one('click', callback);
});
The setTimeout method:
setTimeout(function() {
$(document).one('click', callback);
}, 1);
Both methods work just fine, but here's my question. I have no idea what the performance implications are for either setTimeout or frequent event binding and unbinding. If anyone knows, I'd love to hear it. But more importantly, I'd like some suggestions on how to measure this stuff myself for future situations like this.
I love sites like http://jsperf.com, but I don't know if it would really be helpful for measuring stuff like this.
And obviously, if someone sees a much better solution, I've love to hear it.
I find the double-bind method quite elegant - I think it accurately reflects your actual intent, and it only takes two lines of code.
But another approach is rather than using .one() you could use .on() and update the event object associated with the first event, adding a flag so that the callback will ignore the first time it is called:
function oneCallback(e) {
if (e.originalEvent.firstTimeIn)
return;
alert("This is the one after the current event");
$(document).off("click", oneCallback);
}
$("div.source").click(function(e) {
e.originalEvent.firstTimeIn = true;
$(document).on("click", oneCallback);
});
Demo: http://jsfiddle.net/q5LG4/
EDIT: To address your concerns about not modifying the event object (or any object you don't own) you could store a firstTime flag in a closure. Here's a rather dodgy .oneAfterThis() plugin that takes that approach:
jQuery.fn.oneAfterThis = function(eventName, callback) {
this.each(function() {
var first = true;
function cb() {
if(first){
first = false;
return;
}
callback.apply(this,[].slice.call(arguments));
$(this).off(eventName,cb);
}
$(this).on(eventName, cb);
});
};
$(someseletor).oneAfterThis("click", function() { ... });
I'm sure that could've done that more elegantly (perhaps I should've bothered to look at how jQuery implements .one()), but I just wanted to whip something up quickly as a proof of concept.
Demo: http://jsfiddle.net/q5LG4/1/
Is there a way to allow other bound events to the same object(ex. textbox) to fire/trigger first?
Say 2 events got bound to the same textbox. Both keyup events. In my case there is a plugin binding its own events, but the way the code is written, mine get bound first. I do not want mine to fire first.
$("#firstname").keyup(function() {
// ...is there anyway to allow the other keyup event to fire first, from here?
// do my work here...
}
$("#firstname").keyup(function() {
// the plugin work.
}
I need to use keyup, there is already key down events.
You should really rewrite your code to only have one keyup binding to that event but if that isn't feasible, you could do it dirty with semaphores and separate your functionality from the binding so it can be called from either bind...
var semaphore = 0; // on init
$("#firstname").keyup(function () { // this one should run first
semaphore++;
if (semaphore === 0) {
first_action();
}
}
$("#firstname").keyup(function () { // this one should run second
if (semaphore > 1) { // you know the first event fired
second_action();
}
else if (semaphore < 1) {
first_action();
second_action();
semaphore++;
}
}
Maybe I'm totally missing something about even handling in jQuery, but here's my problem.
Let's assume there are some event binding, like
$(element).bind("mousemove", somefunc);
Now, I'd like to introduce a new mousemove binding that doesn't override the previous one, but temporarily exclude (unbind) it. In other words, when I bind my function, I must be sure that no other functions will ever execute for that event, until I restore them.
I'm looking for something like:
$(element).bind("mousemove", somefunc);
// Somefunc is used regularly
var savedBinding = $(element).getCurrentBinding("mousemove");
$(element).unbind("mousemove").bind("mousemove", myfunc);
// Use myfunc instead
$(element).unbind("mousemove", myfunc).bind("mousemove", savedBindings);
Of course, the somefunc is not under my control, or this would be useless :)
Is my understanding that is possible to bind multiple functions to the same event, and that the execution of those functions can't be pre-determined.
I'm aware of stopping event propagation and immediate event propagation, but I'm thinking that they are useless in my case, as the execution order can't be determined (but maybe I'm getting these wrong).
How can I do that?
EDIT: I need to highlight this: I need that the previously installed handler (somefunc) isn't executed. I am NOT defining that handler, it may be or may be not present, but its installed by a third-party user.
EDIT2: Ok, this is not feasible right now, I think I'm needing the eventListenerList, which is not implemented in most browsers yet. http://www.w3.org/TR/2002/WD-DOM-Level-3-Events-20020208/changes.html
Another way could be to use custom events, something along these lines:
var flag = 0;
$(element).bind("mousemove", function() {
if(flag) {
$(this).trigger("supermousemove");
} else {
$(this).trigger("magicmousemove");
}
}).bind("supermousemove", function() {
// do something super
}).bind("magicmousemove", function() {
// do something magical
});
$("#foo").click(function() {
flag = flag == 1 ? 0 : 1; // simple switch
});
Highly annoying demo here: http://jsfiddle.net/SkFvW/
Good if the event is bound to multiple elements:
$('.foo').click(function() {
if ( ! $(this).hasClass('flag')) {
do something
}
});
(add class 'flag' to sort of unbind, add it to 'bind')