Search code examples
javascriptfunctionvariableseventsevent-handling

Unable to use removeEventListener() to remove a handler from an element


I've added a "click" event listener to a "Delete" button.

deleteButton.addEventListener("click", deleteNote);

This event listener when triggered calls the function below:

let deleteEnabled = false; // global variable

const deleteNote = function () {
  deleteEnabled = !deleteEnabled;
  const noteElements = document.querySelectorAll(".note");

  const setDeleteBorder = function (e) {
    e.target.style.border = "5px solid red";
    e.target.style.borderRadius = "10px";
    e.target.style.cursor = "pointer";
  };

  if (deleteEnabled) {
    noteElements.forEach((el) => {
      el.addEventListener("mouseenter", (e) => setDeleteBorder(e));
      el.addEventListener("mouseleave", (e) => {
        e.target.style.border = "";
        e.target.style.borderRadius = "";
      });
    });
  } else if (!deleteEnabled) {
    noteElements.forEach((el) =>
      el.removeEventListener("mouseenter", (e) => setDeleteBorder(e))
    );
  }
};

The function works, and will add both the mouseenter and mouseleave event listeners to the array of elements, but when the deleteButton is pressed again mouseenter will not be removed by the removeEventListener.

At first i've thought it was a problem with the global variable not being toggled correctly, but when checking the console i've found out that multiple event listeners are being added, and removeEventListener is not removing any of them.

What could be causing this? Could it be a problem related to this pointing to the wrong element? Or is there something i am misunderstanding about removeEventListener?

So far, i've tried using console.log() to verify the value of the deleteEnabled variable, i've also tested with addEventListener and removeEventListener with another element on the global scope and i've managed to remove the event listener in that test. I've also tried renaming the handler that is being used with the event listener. Nothing i've tried so far has worked, and when i press the button, the same event handler keeps being added on top of the element.


Solution

  • The problem is that when you add event listeners inside a loop using an anonymous function,

    Now use the Update Version its working perfectly.

    let deleteEnabled = false;
    
    // Define the event listener outside deleteNote function
    const setDeleteBorder = function (e) {
      e.target.style.border = "5px solid red";
      e.target.style.borderRadius = "10px";
      e.target.style.cursor = "pointer";
    };
    
    const removeDeleteBorder = function (e) {
      e.target.style.border = "";
      e.target.style.borderRadius = "";
    };
    
    const deleteNote = function () {
      deleteEnabled = !deleteEnabled;
      const noteElements = document.querySelectorAll(".note");
    
      if (deleteEnabled) {
        noteElements.forEach((el) => {
          el.addEventListener("mouseenter", setDeleteBorder);
          el.addEventListener("mouseleave", removeDeleteBorder);
        });
      } else {
        noteElements.forEach((el) => {
          el.removeEventListener("mouseenter", setDeleteBorder);
          el.removeEventListener("mouseleave", removeDeleteBorder);
        });
      }
    };
    
    const deleteButton = document.getElementById("deleteButton");
    deleteButton.addEventListener("click", deleteNote);
    .note {
              width: 100px;
              height: 100px;
              background-color: yellow;
              margin: 10px;
            }
    <div class="note">Note 1</div>
    <div class="note">Note 2</div>
    <div class="note">Note 3</div>
    <button id="deleteButton">Delete</button>