web-dev-qa-db-fra.com

Javascript removeEventListener ne fonctionne pas

J'ai le code suivant pour ajouter eventListener

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

Il fonctionne correctement comme prévu .. Plus tard, dans une autre fonction, j'ai essayé de supprimer l'écouteur d'événements à l'aide du code suivant

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

Mais même l'auditeur n'est pas supprimé .. Pourquoi cela se produit-il? Est-ce que mon removeEventListener ()?

46

Cela est dû au fait que deux fonctions anonymes sont des fonctions complètement différentes. L'argument de votre removeEventListener n'est pas une référence à l'objet fonction précédemment attaché.

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

Vous créez deux fonctions différentes dans les deux appels. Donc, la deuxième fonction ne concerne en aucune façon la première et le moteur est capable de la supprimer. Utilisez plutôt un identifiant commun pour la fonction.

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

plus tard, vous pouvez alors supprimer le gestionnaire en appelant

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

Je trouve que pour l'objet windows, le dernier paramètre "true" est requis . La suppression ne fonctionne pas s'il n'y a pas d'indicateur de capture.

1
Slavik

Pour la supprimer, stockez la fonction dans une variable ou utilisez simplement une fonction nommée et transmettez-la à l'appel removeEventListener:

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

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

Si vous souhaitez transmettre des variables locales à la fonction appelée par l'écouteur d'événements, vous pouvez définir la fonction dans la fonction (pour obtenir les variables locales) et transmettre le nom de la fonction dans la fonction elle-même. Par exemple, commençons dans la fonction qui ajoute l'écouteur d'événements avec app en tant que variable locale. Vous écririez une fonction dans cette fonction telle que,

function yourFunction () {
    var app;

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

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

Ensuite, vous avez ce dont vous avez besoin pour le supprimer lorsque waitExecute est appelé.

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

définissez d'abord votre gestionnaire d'événements,

et alors

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

J'ai rencontré un problème avec removeEventListener () qui nécessite une explication.

Je souhaitais pouvoir transmettre des paramètres aux écouteurs d'événements. J'ai donc écrit une fonction pour générer l'écouteur d'événements, qui renvoie à son tour une deuxième fonction, qui appelle mon écouteur d'événements prévu en tant que rappel.

Le fichier de bibliothèque complet est le suivant:

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

Ensuite, j'ai écrit une rapide page de test pour savoir si cela fonctionnait comme prévu et m'a permis d'ajouter ET de supprimer les gestionnaires d'événements à volonté.

La page de test HTML est la suivante:

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

Par souci d’exhaustivité, j’utilise également le fichier CSS simple suivant:

/* 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! */

}

Le code de test est le suivant:

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

Le test à effectuer est donc le suivant:

[1] Associez un gestionnaire d’événements click au bouton n ° 1;

[2] Testez pour voir si le gestionnaire d'événements est appelé lorsque je clique sur le bouton.

[3] Une fois ce test réussi, cliquez sur le bouton n ° 2 et appelez le gestionnaire d'événements associé, ce qui supprime l'ancien gestionnaire d'événements associé au bouton n ° 1, puis le remplace par un nouveau gestionnaire d'événements.

Les étapes [1] et [2] fonctionnent bien. Le gestionnaire d'événements est attaché et invoqué chaque fois que je clique sur le bouton.

Le problème est avec l'étape [3].

Même si j'enregistre une référence à la fonction générée par MakeEventHandler (), notamment dans le but de supprimer cet écouteur d'événement à l'étape [3], l'appel à removeEventListener () ne supprime PAS l'écouteur d'événement. Un clic ultérieur sur le bouton 1 déclenche les DEUX écouteurs d'événement, y compris celui que j'ai supposé avoir supprimé!

Inutile de dire que ce comportement me rend perplexe, malgré le fait que tout est mis en place de manière à ce que la fonction que je spécifie dans l’appel de removeEventListener () soit la même que celle que j’avais ajoutée initialement avec addEventListener () - selon tous la documentation sur le sujet que j'ai lu (y compris ce fil), en passant une référence à la même fonction pour chaque appel devrait fonctionne, mais ne le fait clairement pas.

A l'étape [1], la sortie de test dans la console lit, comme prévu:

Bouton 1 gestionnaire d'événement initial déclenché

Le code est également exécuté, comme prévu, à l'étape [2], et une trace pas à pas du code révèle qu'en réalité, le code est exécuté comme prévu.

Mais à l'étape [3], alors que le premier cliquez sur le bouton n ° 1 donne le résultat souhaité:

Bouton 1 gestionnaire d'événement final déclenché

que se passe-t-il lorsque le bouton 1 est cliqué sur ensuite est-ce:

Bouton 1 gestionnaire d'événement initial déclenché Bouton 1 gestionnaire d'événement final déclenché

Certes, même si la fonction initialement attachée au bouton n ° 1 persiste en mémoire, car elle a été générée dans une fermeture, elle devrait quand même être détachée de la collection d'écouteurs d'événements pour l'élément. Pourquoi est-il toujours connecté?

Ou ai-je déjà rencontré un problème étrange impliquant l'utilisation de fermetures avec des écouteurs d'événement, qui doit être signalé?

0
David Edwards