Javascript removeEventListener not working

2019-01-03 06:26发布

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

7条回答
等我变得足够好
2楼-- · 2019-01-03 07:08

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

查看更多
叛逆
3楼-- · 2019-01-03 07:09

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);
查看更多
你好瞎i
4楼-- · 2019-01-03 07:11

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);
查看更多
爷的心禁止访问
5楼-- · 2019-01-03 07:17

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);
}
查看更多
何必那么认真
6楼-- · 2019-01-03 07:20

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?

查看更多
小情绪 Triste *
7楼-- · 2019-01-03 07:21

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);
查看更多
登录 后发表回答