[javascript] removeEventListener on anonymous functions in JavaScript

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.

This question is related to javascript safari dom-events anonymous-function

The answer is


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


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


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

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


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

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

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


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; };

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";)


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.


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.


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

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);
});

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to safari

How to Inspect Element using Safari Browser What does the shrink-to-fit viewport meta attribute do? background: fixed no repeat not working on mobile Swift Open Link in Safari How do I make flex box work in safari? onClick not working on mobile (touch) window.open(url, '_blank'); not working on iMac/Safari HTML5 Video tag not working in Safari , iPhone and iPad NodeJS/express: Cache and 304 status code Video auto play is not working in Safari and Chrome desktop browser

Examples related to dom-events

Detecting real time window size changes in Angular 4 Does Enter key trigger a click event? What are passive event listeners? Stop mouse event propagation React onClick function fires on render How do you Hover in ReactJS? - onMouseLeave not registered during fast hover over iFrame onload JavaScript event addEventListener, "change" and option selection Automatically pass $event with ng-click? JavaScript click event listener on class

Examples related to anonymous-function

removeEventListener on anonymous functions in JavaScript How to sort with lambda in Python How can I write an anonymous function in Java? Is it valid to define functions in JSON results? Why do you need to invoke an anonymous function on the same line? How can I pass a reference to a function, with parameters?