72

Is there anyway to remove an event listener added like this:

element.addEventListener(event, function(){/* do work here */}, false);

Without replacing the element?

Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
erikvold
  • 15,988
  • 11
  • 54
  • 98

14 Answers14

37

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.

Joe
  • 2,407
  • 18
  • 20
  • 10
    i wonder why addeventlistener doesn't return such a reference for future use by removeeventlistener... – Michael Aug 27 '17 at 19:40
  • It does, this is what you save. – Joe May 09 '18 at 14:32
  • 2
    @Joe and for users coming late here: `addEventListener` returns `undefined` at least in some cases. For example in a BroadcastChannel context. – BairDev Sep 19 '18 at 07:05
  • Note that, as per https://stackoverflow.com/a/27107765/377022, in Chrome console, you can use the `getEventListeners` function – Jason Gross Dec 29 '18 at 08:28
  • @JasonGross Yes, the APIs have much improved since WebKit in 2010 when I created this answer. – Joe Jan 08 '19 at 18:51
  • 1
    @Joe Sure. It might be nice to update the officially-accepted answer so that people who come looking to this as a reference in the future (as I did) are aware of the new developments. – Jason Gross Jan 08 '19 at 18:58
  • I haven't done extensive JavaScript development in 5 years or so. I'm happy for someone to edit it to be correct. I'm more back end and embedded work now and not current in modern JavaScript anymore. Although that link mentions that this is only available in console and the request was for doing it progromatically. I don't know if this has changed at all. – Joe Jan 08 '19 at 19:09
  • For future readers, @OllieWilliams' answer may be useful: https://stackoverflow.com/a/72673200/1042398 – Mike Willis Jan 23 '23 at 22:04
25

You could remove the event listener like this:

element.addEventListener("click", function clicked() {
    element.removeEventListener("click", clicked, false);
}, false);
icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • 8
    That only works if you are adding the event listener in the first place -- that you can modify the original listener() code. Since this is a Greasemonkey application, that is not possible. Even if the base-page script was changed, you'd only be adding *another* anonymous listener. – Brock Adams Jun 24 '10 at 04:37
  • 1
    @Brock: Oh, I thought the intention was to remove a listener you added. I don't know of any way to remove a listener you didn't add and have no reference to the function of. – icktoofay Jun 24 '10 at 04:42
  • Brock is correct, this is a question for user scripting, but good answer none the less, I gave it an up vote! – erikvold Jun 24 '10 at 09:42
  • 1
    You may want to add that `callee` is deprecated since ES5 (see [mdn](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FFunctions_and_function_scope%2Farguments%2Fcallee) or [SO](http://stackoverflow.com/questions/103598/why-was-the-arguments-callee-caller-property-deprecated-in-javascript) ) – merours Mar 20 '15 at 16:05
  • @fxm: Thanks. I don’t remember why I originally used `arguments.callee` and a named function expression ought to work fine, so I edited my answer. – icktoofay Mar 23 '15 at 07:45
  • Is `clicked` function visible within itself? I have some problems with this: https://stackoverflow.com/questions/70991363/failed-to-store-the-reference-of-event-handler-i-want-to-remove-the-event-liste – shen Feb 04 '22 at 21:29
20

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>
Community
  • 1
  • 1
20

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.

Manngo
  • 14,066
  • 10
  • 88
  • 110
  • 1
    Like this solution am going to use it. Can't think if it matters or not, but there will still be a reference to the function afterward e.g. calling element.fn() will still return the result of the function. Could this be a memory issue if not cleaned up? – Jarrod McGuire Nov 28 '18 at 15:02
8

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();
Ollie Williams
  • 1,996
  • 3
  • 25
  • 41
5

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)

w35l3y
  • 8,613
  • 3
  • 39
  • 51
3

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.

kennebec
  • 102,654
  • 32
  • 106
  • 127
  • "You can't" in summary? which is what I think is the correct answer. – erikvold Jun 24 '10 at 02:46
  • You can, if you assign them as properties, and not using addEventListener. element.onmouseover=function(){dothis}; element.onmouseover=''; – kennebec Jun 24 '10 at 03:40
  • 2
    In Greasemonkey applications, we don't have any control over how events are created in the base page. FYI, in a GM script, something like `element.onmouseover=function` won't work anyway, because of sandbox protection. See http://commons.oreilly.com/wiki/index.php/Greasemonkey_Hacks/Getting_Started#Pitfall_.232:_Event_Handlers . – Brock Adams Jun 24 '10 at 04:25
2

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.

general64
  • 37
  • 1
  • 1
  • 7
  • 2
    Back to the question, jQuery actually stores a reference to the function and then adds the function. This is why you don’t need to specify _which_ function you are removing. That is, it’s not anonymous by the time it is added. BTW, jQuery prefers `.off()` to `.unbind()`. – Manngo Jul 07 '18 at 09:04
  • 1
    why give a jquery answer for a JS question? – ortonomy May 12 '21 at 08:25
1

If you're using jQuery try off method

$("element").off("event");
uingtea
  • 6,002
  • 2
  • 26
  • 40
1

Jquery .off() method removes event handlers that were attached with .on()

femi-adenubi
  • 11
  • 1
  • 3
1

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);
})();
DDRRSS
  • 306
  • 3
  • 8
1
//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

0

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!)

funtkungus
  • 238
  • 1
  • 2
  • 12
-2

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);
Ice101781
  • 105
  • 10