javascripthtmlevent-listenerremoveeventlistener

removeEventListener() not working with multiple elements in a for loop [Javascript]


I've been testing around to see if you can prevent having duplicate event listeners

The code below loops through all the buttons with a certain attribute.

the problem is it only works with ONE button

let LOGIC;
let removeListener = undefined;
let test = document.getElementById("test")
let allButtons = document.querySelectorAll("input[btn]")

function GameLogic(btn, test) {
test.innerHTML = eval(`${test.textContent} + 1`)
btn.value += "1"
}


let Apply = function() {
for (let i = 0; i < allButtons.length; i++) {
if (removeListener == true){
allButtons[i].removeEventListener("click", LOGIC)
}
LOGIC = GameLogic.bind(null, allButtons[i], test)
allButtons[i].addEventListener("click", LOGIC);
removeListener = true
}
}

document.getElementById("redo").addEventListener("click", Apply)

Here is the HTML:

<input type = "button" id = "DIE" btn value = "Click Me">
<input type = "button" id = "DIE" btn value = "Click Me">
<input type = "button" id = "DIE" btn value = "Click Me">
<input type = "button" id = "DIE" btn value = "Click Me">
<button id = "redo"> Redo Function </button>
<p id = "test">0</p>

I've tried so many different solutions and nothing really worked.

The logic seemed to add up the in the aforementioned code.


Solution

  • First of all, in your function Accept, the statement removeListener = true seems to be in the wrong place.

    let Apply = function () {
        for (let i = 0; i < allButtons.length; i++) {
            if (removeListener == true) {
                allButtons[i].removeEventListener("click", LOGIC)
            }
            LOGIC = GameLogic.bind(null, allButtons[i], test)
            allButtons[i].addEventListener("click", LOGIC);
            removeListener = true //Set as true for the first button
        }
    }
    

    Instead of :

    let Apply = function () {
        for (let i = 0; i < allButtons.length; i++) {
            if (removeListener == true) {
                allButtons[i].removeEventListener("click", LOGIC)
            }
            LOGIC = GameLogic.bind(null, allButtons[i], test)
            allButtons[i].addEventListener("click", LOGIC);
        }
        removeListener = true //Set as true after the first loop has run
    }
    

    Second issue is your variable LOGIC. As it is changed in every steps of the loop, when you click on Redo, you have the value for the last button instead of the first. A solution could be to use an array like this :

    let LOGICS = []; //Now is an array
    let removeListener = undefined;
    let test = document.getElementById("test")
    let allButtons = document.querySelectorAll("input[btn]")
    
    function GameLogic(btn, test) {
        test.innerHTML = eval(`${test.textContent} + 1`)
        btn.value += "1"
    }
    
    let Apply = function () {
        for (let i = 0; i < allButtons.length; i++) {
            if (removeListener == true) {
                allButtons[i].removeEventListener("click", LOGICS[i])//So when your remove the event listener, it is the function you have used to add it who is passed
            }
            LOGICS[i] = GameLogic.bind(null, allButtons[i], test)
            allButtons[i].addEventListener("click", LOGICS[i]);
        }
        removeListener = true
    }
    
    document.getElementById("redo").addEventListener("click", Apply)