thomas
thomas

Reputation: 2241

How can I remove a JavaScript event listener?

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...

Upvotes: 224

Views: 409824

Answers (12)

Mubtasim Fuad
Mubtasim Fuad

Reputation: 1

Remember, you must give every function a name because the name serves as the function's identifier.

If you do not assign a name to a function, it cannot be removed from a JavaScript event listener.

Example of a named function:

 function closePop(event =new Event('click') ) {}

Example of an arrow function:

const closePop=(event =new Event('click'))=>{};

Now, if you want to remove an event listener:

cancelBtn.addEventListener('click', function closePop(event =new Event('click') ) {
            cancelBtn.removeEventListener('click', closePop);
            
        })

For an arrow function:


let f=()=>{
    cancelBtn.removeEventListener('click', f);

};
cancelBtn.addEventListener('click',f )

Upvotes: -1

Magnus Lind Oxlund
Magnus Lind Oxlund

Reputation: 351

Signals is a new way to remove an event listener without reference to the callback function or the exact arguments used when registering it.

You'll need a signal object passed to addEventListener:

const controller = new AbortController();
randomElement.addEventListener('click', randomCallback, {'signal':controller.signal});

Once that's done, you can use the AbortController's abort method to send the abort signal:

controller.abort();

All event listeners hooked up to that controller will be canceled with a single method call. The effect is identical to using removeEventListener.

Many other answers on this page demonstrate how removeEventListener can be inflexible. Signals opens up the door to canceling anonymous and arrow function-based event listeners without currying or otherwise storing a reference to the callback.

Upvotes: 1

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 send an abort signal and have JS do the rest without needing to save our event handling function somewhere and then calling removeEventListener with the exact same combination of arguments as we registered the listener:

const controller = new AbortController();

canvas.addEventListener('click', () => {
  click++;
  if (click === 50) {
    // Cancel and clean up the event using our controller:
    controller.abort();
  } else {
    doSomethingWith(click);
  }
}, {
  // Tie our controller to this event binding:
  signal: controller.signal
});

(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 once controller.abort() gets called, without having to call removeEventListener with the exact same function and properties as we called addEventListener: just cancel the listener.

And of course, the value here is in the fact that we can use a single controller to abort multiple events simultaneously, so we can clean up some UI's touchstart, touchend, mouseenter, mouseleave, click, focus, blur, and window scroll, all with a single call to .abort(). No tracking event handlers, just have a reference to that single controller tied to your UI component, and set up the event handling to listen for its signal when it gets removed from the DOM.

Upvotes: 13

user113716
user113716

Reputation: 322582

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

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

Upvotes: 199

Luis Americo
Luis Americo

Reputation: 13

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

Upvotes: -3

Tama
Tama

Reputation: 1715

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/.

Upvotes: 102

user3870075
user3870075

Reputation: 141

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>

Upvotes: -7

youssman
youssman

Reputation: 1524

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

Upvotes: 4

Vinyl Windows
Vinyl Windows

Reputation: 503

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

Upvotes: 8

Ender
Ender

Reputation: 15221

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.

Upvotes: 6

edeverett
edeverett

Reputation: 8218

   canvas.addEventListener('click', function(event) {
      click++;
      if(click == 50) {
          this.removeEventListener('click',arguments.callee,false);
      }

Should do it.

Upvotes: 102

Brad Christie
Brad Christie

Reputation: 101614

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

Upvotes: 16

Related Questions