removeEventListener on anonymous functions in JavaScript

JavascriptSafariDom EventsAnonymous Function

Javascript Problem Overview


I have an object that has methods in it. These methods are put into the object inside an anonymous function. It looks like this:

var t = {};
window.document.addEventListener("keydown", function(e) {
    t.scroll = function(x, y) {
        window.scrollBy(x, y);
    };
    t.scrollTo = function(x, y) {
        window.scrollTo(x, y);
    };
});  

(there is a lot more code, but this is enough to show the problem)

Now I want to stop the event listener in some cases. Therefore I am trying to do a removeEventListener but I can't figure out how to do this. I have read in other questions that it is not possible to call removeEventListener on anonymous functions, but is this also the case in this situation?

I have a method in t created inside the anonymous function and therefore I thought it was possible. Looks like this:

t.disable = function() {
    window.document.removeEventListener("keydown", this, false);
}

Why can't I do this?

Is there any other (good) way to do this?

Bonus info; this only has to work in Safari, hence the missing IE support.

Javascript Solutions


Solution 1 - Javascript

if you are inside the actual function, you can use arguments.callee as a reference to the function. as in:

button.addEventListener('click', function() {
      ///this will execute only once
      alert('only once!');
      this.removeEventListener('click', arguments.callee);
});

EDIT: This will not work if you are working in strict mode ("use strict";)

Solution 2 - Javascript

I believe that is the point of an anonymous function, it lacks a name or a way to reference it.

If I were you I would just create a named function, or put it in a variable so you have a reference to it.

var t = {};
var handler = function(e) {
    t.scroll = function(x, y) {
        window.scrollBy(x, y);
    };
    t.scrollTo = function(x, y) {
        window.scrollTo(x, y);
    };
};
window.document.addEventListener("keydown", handler);

You can then remove it by

window.document.removeEventListener("keydown", handler);   

Solution 3 - Javascript

A version of Otto Nascarella's solution that works in strict mode is:

button.addEventListener('click', function handler() {
      ///this will execute only once
      alert('only once!');
      this.removeEventListener('click', handler);
});

Solution 4 - Javascript

in modern browsers you can do the following...

button.addEventListener( 'click', () => {
    alert( 'only once!' );
}, { once: true } );

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Parameters

Solution 5 - Javascript

window.document.removeEventListener("keydown", getEventListeners(window.document.keydown[0].listener));  

May be several anonymous functions, keydown1

Warning: only works in Chrome Dev Tools & cannot be used in code: link

Solution 6 - Javascript

This is not ideal as it removes all, but might work for your needs:

z = document.querySelector('video');
z.parentNode.replaceChild(z.cloneNode(1), z);

> Cloning a node copies all of its attributes and their values, including > intrinsic (in–line) listeners. It does not copy event listeners added using > addEventListener()

Node.cloneNode()

Solution 7 - Javascript

A not so anonymous option

element.funky = function() {
    console.log("Click!");
};
element.funky.type = "click";
element.funky.capt = false;
element.addEventListener(element.funky.type, element.funky, element.funky.capt);
// blah blah blah
element.removeEventListener(element.funky.type, element.funky, element.funky.capt);

Since receiving feedback from Andy (quite right, but as with many examples, I wished to show a contextual expansion of the idea), here's a less complicated exposition:

<script id="konami" type="text/javascript" async>
    var konami = {
        ptrn: "38,38,40,40,37,39,37,39,66,65",
        kl: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
    };
    document.body.addEventListener( "keyup", function knm ( evt ) {
        konami.kl = konami.kl.slice( -9 );
        konami.kl.push( evt.keyCode );
        if ( konami.ptrn === konami.kl.join() ) {
            evt.target.removeEventListener( "keyup", knm, false );

            /* Although at this point we wish to remove a listener
               we could easily have had multiple "keyup" listeners
               each triggering different functions, so we MUST
               say which function we no longer wish to trigger
               rather than which listener we wish to remove.

               Normal scoping will apply to where we can mention this function
               and thus, where we can remove the listener set to trigger it. */

            document.body.classList.add( "konami" );
        }
    }, false );
    document.body.removeChild( document.getElementById( "konami" ) );
</script>

This allows an effectively anonymous function structure, avoids the use of the practically deprecated callee, and allows easy removal.

Incidentally: The removal of the script element immediately after setting the listener is a cute trick for hiding code one would prefer wasn't starkly obvious to prying eyes (would spoil the surprise ;-)

So the method (more simply) is:

element.addEventListener( action, function name () {
    doSomething();
    element.removeEventListener( action, name, capture );
}, capture );

Solution 8 - Javascript

JavaScript: addEventListener method registers the specified listener on the EventTarget(Element|document|Window) it's called on.

EventTarget.addEventListener(event_type, handler_function, Bubbling|Capturing);

Mouse, Keyboard events Example test in WebConsole:

var keyboard = function(e) {
    console.log('Key_Down Code : ' + e.keyCode);
};
var mouseSimple = function(e) {
	var element = e.srcElement || e.target;
	var tagName = element.tagName || element.relatedTarget;
	console.log('Mouse Over TagName : ' + tagName);	   
};
var  mouseComplex = function(e) {
	console.log('Mouse Click Code : ' + e.button);
} 

window.document.addEventListener('keydown',   keyboard,      false);
window.document.addEventListener('mouseover', mouseSimple,   false);
window.document.addEventListener('click',     mouseComplex,  false);

removeEventListener method removes the event listener previously registered with EventTarget.addEventListener().

window.document.removeEventListener('keydown',   keyboard,     false);
window.document.removeEventListener('mouseover', mouseSimple,  false);
window.document.removeEventListener('click',     mouseComplex, false);

caniuse

Solution 9 - Javascript

To give a more up-to-date approach to this:

//one-time fire
element.addEventListener('mousedown', {
  handleEvent: function (evt) {
    element.removeEventListener(evt.type, this, false);
  }
}, false);

Solution 10 - Javascript

I have stumbled across the same problem and this was the best solution I could get:

/*Adding the event listener (the 'mousemove' event, in this specific case)*/
element.onmousemove = function(event) {
    /*do your stuff*/
};
/*Removing the event listener*/
element.onmousemove = null;

Please keep in mind I have only tested this for the window element and for the 'mousemove' event, so there could be some problems with this approach.

Solution 11 - Javascript

There's a new way to do this that is supported by the latest versions of most popular browsers with the exception of Safari.

Check caniuse for updated support.

We can add an option to addEventListner called signal and assign a signal from an AbortController on which you can later call the abort() method.

Here is an example.

We create an AbortController:

const controller = new AbortController();

Then we create the eventListner and pass in the option signal:

document.addEventListener('scroll',()=>{
    // do something
},{signal: controller.signal})

And then to remove the eventListner at a later time, we call:

controller.abort()

Solution 12 - Javascript

Possibly not the best solution in terms of what you are asking. I have still not determined an efficient method for removing anonymous function declared inline with the event listener invocation.

I personally use a variable to store the <target> and declare the function outside of the event listener invocation eg:

const target = document.querySelector('<identifier>');

function myFunc(event) { function code; }

target.addEventListener('click', myFunc);

Then to remove the listener:

target.removeEventListener('click', myFunc);

Not the top recommendation you will receive but to remove anonymous functions the only solution I have found useful is to remove then replace the HTML element. I am sure there must be a better vanilla JS method but I haven't seen it yet.

Solution 13 - Javascript

I know this is a fairly old thread, but thought I might put in my two cents for those who find it useful.

The script (apologies about the uncreative method names):

window.Listener = {
	_Active: [],
	remove: function(attached, on, callback, capture){
		for(var i = 0; i < this._Active.length; i++){
			var current = this._Active[i];
			if(current[0] === attached && current[1] === on && current[2] === callback){
				attached.removeEventListener(on, callback, (capture || false));
				return this._Active.splice(i, 1);
			}
		}
	}, removeAtIndex(i){
		if(this._Active[i]){
			var remove = this._Active[i];
			var attached = remove[0], on = remove[1], callback = remove[2];
			attached.removeEventListener(on, callback, false);
			return this._Active.splice(i, 1);
		}
	}, purge: function(){
		for(var i = 0; i < this._Active.length; i++){
			var current = this._Active[i];
			current[0].removeEventListener(current[1], current[2]);
			this._Active.splice(i, 1);
		}
	}, declare: function(attached, on, callback, capture){
		attached.addEventListener(on, callback, (capture || false));
		if(this._Active.push([attached, on, callback])){
			return this._Active.length - 1;
		}
	}
};

And you can use it like so:

// declare a new onclick listener attached to the document
var clickListener = Listener.declare(document, "click" function(e){
    // on click, remove the listener and log the clicked element
    console.log(e.target);
    Listener.removeAtIndex(clickListener);
});

// completely remove all active listeners 
// (at least, ones declared via the Listener object)
Listener.purge();

// works exactly like removeEventListener
Listener.remove(element, on, callback);

Solution 14 - Javascript

I just experienced similiar problem with copy-protection wordpress plugin. The code was:

function disableSelection(target){
 if (typeof target.onselectstart!="undefined") //For IE 
  target.onselectstart=function(){return false}
 else if (typeof target.style.MozUserSelect!="undefined") //For Firefox
  target.style.MozUserSelect="none"
 else //All other route (For Opera)
  target.onmousedown=function(){return false}
target.style.cursor = "default"
}

And then it was initiated by loosely put

<script type="text/javascript">disableSelection(document.body)</script>.

I came around this simply by attaching other annonymous function to this event:

document.body.onselectstart = function() { return true; };

Solution 15 - Javascript

Set anonymous listener:

document.getElementById('ID').addEventListener('click', () => { alert('Hi'); });

Remove anonymous listener:

document.getElementById('ID').removeEventListener('click',getEventListeners(document.getElementById('ID')).click[0].listener)

Solution 16 - Javascript

window.document.onkeydown = function(){};

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbitkidView Question on Stackoverflow
Solution 1 - JavascriptOtto NascarellaView Answer on Stackoverflow
Solution 2 - JavascriptAdam HeathView Answer on Stackoverflow
Solution 3 - JavascriptMelleView Answer on Stackoverflow
Solution 4 - Javascriptshunryu111View Answer on Stackoverflow
Solution 5 - JavascriptIsayevskiy_SergeyView Answer on Stackoverflow
Solution 6 - Javascriptuser4427511View Answer on Stackoverflow
Solution 7 - JavascriptFred GandtView Answer on Stackoverflow
Solution 8 - JavascriptYashView Answer on Stackoverflow
Solution 9 - JavascriptJonatas WalkerView Answer on Stackoverflow
Solution 10 - JavascriptGark GarciaView Answer on Stackoverflow
Solution 11 - JavascriptH KView Answer on Stackoverflow
Solution 12 - JavascriptShay ConnollyView Answer on Stackoverflow
Solution 13 - JavascriptGROVER.View Answer on Stackoverflow
Solution 14 - JavascriptWojtek MazurekView Answer on Stackoverflow
Solution 15 - JavascriptAndreyView Answer on Stackoverflow
Solution 16 - JavascriptDunView Answer on Stackoverflow