Javascript removeEventListener not working

JavascriptEventsAddeventlistener

Javascript Problem Overview


I have the following code to add eventListener

 area.addEventListener('click',function(event) {
		      app.addSpot(event.clientX,event.clientY);
		      app.addFlag = 1;
		  },true);

It is working correctly as expected..Later in another function i tried to remove the event listener using the following code

 area.removeEventListener('click',function(event) {
		      app.addSpot(event.clientX,event.clientY);
		      app.addFlag = 1;
		  },true);

But the even listener is not removed..Why is it happening?Is there any problem with my removeEventListener()? Note:Here area is something like document.getElementById('myId')

Javascript Solutions


Solution 1 - Javascript

This is because that two anonymous functions are completely different functions. Your removeEventListener's argument is not a reference to the function object that was previously attached.

function foo(event) {
              app.addSpot(event.clientX,event.clientY);
              app.addFlag = 1;
          }
 area.addEventListener('click',foo,true);
 area.removeEventListener('click',foo,true);

Solution 2 - Javascript

I find that for the windows object, the last param "true" is required. The remove doesn't work if there is no capture flag.

Solution 3 - Javascript

In a React function component, make sure to define the callback with the useCallback(() => {}) hook. If you fail to do this, the callback will be a different one on every re-render and the removeEventListener method will not work.

const scrollCallback = useCallback(() => { // do sth. });
window.addEventListener("scroll", scrollCallback, true);
window.removeEventListener("scroll", scrollCallback, true);

Solution 4 - Javascript

You are creating two different functions in both calls. So the second function does not relate in any way to the first one and the engine is able to remove the function. Use a common identifier for the function instead.

var handler = function(event) {
              app.addSpot(event.clientX,event.clientY);
              app.addFlag = 1;
          };
area.addEventListener('click', handler,true);

later you can then remove the handler by calling

area.removeEventListener('click', handler,true);

Solution 5 - Javascript

To remove it, store the function in a variable or simply use a named function and pass that function to the removeEventListener call:

function areaClicked(event) {
    app.addSpot(event.clientX, event.clientY);
    app.addFlag = 1;
}

area.addEventListener('click', areaClicked, true);
// ...
area.removeEventListener('click', areaClicked, true);

Solution 6 - Javascript

If you want to pass local variables to the function called by the event listener, you can define the function inside the function (to get the local variables) and pass the name of the function in the function itself. For example, let's start inside the function that adds the event listener with app as a local variable. You would write a function inside this function such as,

function yourFunction () {
    var app;

    function waitListen () {
        waitExecute(app, waitListen);
    }

    area.addEventListener('click', waitListen, true);
}

Then you have what you need to remove it when waitExecute is called.

function waitExecute (app, waitListen) {
    ... // other code
    area.removeEventListener('click', waitListen, true);
}

Solution 7 - Javascript

define your Event Handler first,

and then

area.addEventListener('click',handler);
area.removeEventListener('click',handler);

Solution 8 - Javascript

I've encountered a problem with removeEventListener() that needs explaining.

I wanted to be able to pass parameters to event listeners, so I wrote a function to generate the event listener, that in turn returns a second function, which calls my intended event listener as a callback.

The complete library file is as follows:

//Event handler constants

function EventHandlerConstants()
{
this.SUCCESS = 0;	//Signals success of an event handler function
this.NOTFUNCTION = 1;	//actualHandler argument passed to MakeEventHandler() is not a Function object

//End constructor
}

//MakeEventHandler()

//Arguments:

//actualHandler	: reference to the actual function to be called as the true event handler

//selfObject	: reference to whatever object is intended to be referenced via the "this" keyword within
//			the true event handler. Set to NULL if no such object is needed by your true
//			event handler specified in the actualHandler argument above.

//args		: array containing the arguments to be passed to the true event handler, so that the true
//			event handler can be written with named arguments, such as:

//			myEventHandler(event, arg1, arg2, ... )

//			If your function doesn't need any arguments, pass an empty array, namely [], as the
//			value of this argument.

//Usage:

//c = new EventHandlerConstants();
//res = MakeEventHandler(actualHandler, selfObject, args);
//if (res == c.SUCCESS)
//	element.addEventListener(eventType, res.actualHandler, true);	//or whatever


function MakeEventHandler(actualHandler, selfObject, args)
{
var c = new EventHandlerConstants();

var funcReturn = null;		//This will contain a reference to the actual function generated and passed back to
				//the caller

var res = {
		"status" : c.SUCCESS,
		"actualHandler" : null
		};

if (IsGenuineObject(actualHandler, Function))
{
	res.actualHandler = function(event) {

		var trueArgs = [event].concat(args);

		actualHandler.apply(selfObject, trueArgs);

	};

}
else
{
	res.status = c.NOTFUNCTION;

//End if/else
}

//Return our result object with appropriate properties set ...

return(res);

//End function
}

Then I wrote a quick test page to find out if this worked as intended, and allowed me to add AND remove event handlers at will.

The HTML test page is as follows:

<!DOCTYPE html>
<html>
<head>

<!-- CSS goes here -->

<link rel="stylesheet" type="text/css" href="NewEventTest.css">

<!-- Required JavaScript library files -->

<script language = "JavaScript" src="BasicSupport.js"></script>
<script language = "JavaScript" src="EventHandler6.js"></script>

</head>

<body class="StdC" id="MainApplication">

<button type="button" class="StdC NoSwipe" id="Button1">Try Me Out</button>

<button type="button" class="StdC NoSwipe" id="Button2">Alter The 1st Button</button>

</body>

<script language = "JavaScript" src="NewEventTest.js"></script>

</html>

For completeness, I use the following simple CSS file as well:

/* NewEventTest.css */


/* Define standard display settings classes for a range of HTML elements */

.StdC {

color: rgba(255, 255, 255, 1);
background-color: rgba(0, 128, 0, 1);
font-family: "Book Antiqua", "Times New Roman", "Times", serif;
font-size: 100%;
font-weight: normal;
text-align: center;

}


.NoSwipe {

user-select: none;	/* Stops text from being selectable! */

}

The test code is as follows:

//NewEventTest.js


function GlobalVariables()
{
this.TmpRef1 = null;
this.TmpRef2 = null;
this.TmpRef3 = null;

this.Const1 = null;

this.Handler1 = null;
this.Handler2 = null;
this.Handler3 = null;

this.EventOptions = {"passive" : true, "capture" : true };

//End constructor
}


//Button 1 Initial function

function Button1Initial(event)
{
console.log("Button 1 initial event handler triggered");

//End event handler
}


function Button1Final(event)
{
console.log("Button 1 final event handler triggered");

//End event handler
}


function Button2Handler(event, oldFunc, newFunc)
{
var funcRef = null;

this.removeEventListener("click", oldFunc);
this.addEventListener("click", newFunc, GLOBALS.EventOptions);

//End event handler
}


//Application Setup

GLOBALS = new GlobalVariables();

GLOBALS.Const1 = new EventHandlerConstants();

GLOBALS.TmpRef1 = document.getElementById("Button1");
GLOBALS.TmpRef2 = MakeEventHandler(Button1Initial, null, []);
if (GLOBALS.TmpRef2.status == GLOBALS.Const1.SUCCESS)
{
	GLOBALS.Handler1 = GLOBALS.TmpRef2.actualHandler;
	GLOBALS.TmpRef1.addEventListener("click", GLOBALS.Handler1, GLOBALS.EventOptions);

//End if
}

GLOBALS.TmpRef1 = MakeEventHandler(Button1Final, null, []);
if (GLOBALS.TmpRef1.status == GLOBALS.Const1.SUCCESS)
{
	GLOBALS.Handler3 = GLOBALS.TmpRef1.actualHandler;

//End if
}


GLOBALS.TmpRef1 = document.getElementById("Button2");
GLOBALS.TmpRef2 = document.getElementById("Button1");
GLOBALS.TmpRef3 = Button1Final;
GLOBALS.TmpRef4 = MakeEventHandler(Button2Handler, GLOBALS.TmpRef2, [GLOBALS.Handler1, GLOBALS.Handler3]);
if (GLOBALS.TmpRef4.status == GLOBALS.Const1.SUCCESS)
{
	GLOBALS.Handler2 = GLOBALS.TmpRef4.actualHandler;
	GLOBALS.TmpRef1.addEventListener("click", GLOBALS.Handler2, GLOBALS.EventOptions);

//End if
}

So, the test to be performed is as follows:

[1] Attach a click event handler to Button #1;

[2] Test to see if the event handler is invoked when I click on the button;

[3] Once that test is passed, click on Button #2, and invoke the event handler attached thereto, which removes the old event handler attached to Button #1, then replaces it with a new event handler.

Steps [1] and [2] work fine. The event handler is attached, and invoked whenever I click upon the button.

The problem is with Step [3].

Even though I save a reference to the function generated by MakeEventHandler(), specifically for the purpose of removing that event listener in Step [3], the call to removeEventListener() does NOT remove the event listener. Subsequent clicking on Button #1 fires BOTH event listeners, including the one I supposedly removed!

Needless to say, this behaviour I find puzzling, despite carefully setting everything up so that the function I specify in the call to removeEventListener() is the self same function I added initially with addEventListener() - according to all the documentation on the subject I've read (including this thread), passing a reference to the same function for each call should work, but clearly doesn't.

At Step [1], the test output in the console reads, as expected:

> Button 1 initial event handler triggered

The code is also run, as expected, in Step [2], and a step by step trace of the code reveals that indeed, the code is executed as expected.

But in Step [3], whilst the first click on Button #1 yields the desired result:

> Button 1 final event handler triggered

what happens when Button #1 is clicked upon subsequently is this:

> Button 1 initial event handler triggered > Button 1 final event handler triggered

Surely, even if the function initially attached to Button #1 still persists in memory, because it was generated within a closure, it should still be detached from the event listener collection for the element? Why is it still connected?

Or have I encountered some weird bug involving using closures with event listeners, that needs to be reported?

Solution 9 - Javascript

This is what I ended up doing but it's in a route class but should not make much difference, I wanted for the event listener not to accumulate each time afterModel() is called but also needed arguments and scope so that the model is changed each time.

export default class iFrameRoute extends Route {

      afterModel(model) {

           this.initFrame = function(event) {  
    
               alert("I am being called");

               window.removeEventListener("message",  this.route.test); 

           }.bind({route: this, data: model});

           window.addEventListener("message",  this.initFrame ); 
       } 
}

Solution 10 - Javascript

I have a system with pagination of data, this function provide many inforrmation do create table and insert new registers, so, in any navigation I must add a eventlistener on ADD button, the best way I found is destroy element and create again before add eventlistener, this worked fine to me

Solution 11 - Javascript

if you are facing issue of removing event listener in functional component of react js then there is issue function reference get's change on every re-render and when you try to remove it's reference reference is already changed which disallow you to remove that event listener. react provide hook to persist the reference of function even functional components get re-render multiple times. wrap the event listener call back function in useCallback hook and it's reference remains the same even function re-render multiple times

const function = useCallback((e) => {

}, [])

Solution 12 - Javascript

It looks like no one's covered the part of the JavaScript specification that now 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 tell the JS engine to remove an event listener by just calling abort() instead of having to bother with removeEventListener:

const areaListener = (new AbortController()).signal;

area.addEventListener(
  `click`,
  function(event) {
    app.addSpot(event.clientX, event.clientY);
    app.addFlag = 1;
  },
  { signal: areaListener }
);

(Note that this does not use the useCapture flag, because the useCapture flag is essentially completely useless)

And now, when it's time to remove that event listener, we simply run:

areaListener.abort()

And done: the JS engine will abort and clean up our event listener. No keeping a reference to the handling function, no making sure we call removeEventListener with the exact same properties as we called addEventListener: we just cancel the listener.

Solution 13 - Javascript

while adding function store in array and removing pass by map work for me

const [functionObjects, setfunctionObjects] = useState([]);

const addListener = (beforeUnloadListener) =>{ setfunctionObjects([...nano, beforeUnloadListener]); addEventListener("beforeunload", beforeUnloadListener, {capture: true}); };

const removeListener = (beforeUnloadListener) => { functionObjects.map((item) => { removeEventListener("beforeunload", item, {capture: true});});};

Solution 14 - Javascript

I went through this same problem recently. A reasonble solution that I found was remove attribute "onclick" on element from HTMLElement class.

Let's imagine that you already got your component from DOM - using document.getElementById or document.querySelector - you can try that code:

js

const element = document.getElementById("myelement");
element.attributes.removeNamedItem('onclick');

html example

<div onClick="memoryGame.flipCard(this)">
   .... // children elements
</div>

I know which this solution it ins't the best, but it works!

I hope I was able to help you.

Cheers!

PS: please, give me a "useful answer"... thanks :D

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
QuestionJinu Joseph DanielView Question on Stackoverflow
Solution 1 - JavascriptduriView Answer on Stackoverflow
Solution 2 - JavascriptSlavikView Answer on Stackoverflow
Solution 3 - Javascriptph1lb4View Answer on Stackoverflow
Solution 4 - JavascriptSirkoView Answer on Stackoverflow
Solution 5 - JavascriptThiefMasterView Answer on Stackoverflow
Solution 6 - JavascriptVectorVortecView Answer on Stackoverflow
Solution 7 - JavascriptneohopeView Answer on Stackoverflow
Solution 8 - JavascriptDavid EdwardsView Answer on Stackoverflow
Solution 9 - JavascriptEpirocksView Answer on Stackoverflow
Solution 10 - JavascriptWyllyan FrankllynView Answer on Stackoverflow
Solution 11 - JavascriptIhtisham TanveerView Answer on Stackoverflow
Solution 12 - JavascriptMike 'Pomax' KamermansView Answer on Stackoverflow
Solution 13 - JavascriptSumit AsagaonkarView Answer on Stackoverflow
Solution 14 - JavascriptMarlon KlagenbergView Answer on Stackoverflow