Home > Software engineering >  removeEventListener() not working with multiple elements in a for loop [Javascript]
removeEventListener() not working with multiple elements in a for loop [Javascript]

Time:12-08

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.

CodePudding user response:

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)

CodePudding user response:

The id attribute needs to be unique. You have multiple buttons with the same id ("DIE"). That's not allowed and makes the html invalid

CodePudding user response:

Instead of setting removeListener as true inside the for loop, you have to put that outside. Here you have used a LOGIC variable that is changed after every iteration and finally you've got the last value of that variable. You can use an array that works better.

let LOGICS = [];
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]);
        }
        LOGICS[i] = GameLogic.bind(null, allButtons[i], test);
        allButtons[i].addEventListener("click", LOGICS[i]);
    }
    removeListener = true;
}

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

JS array and DOM manipulation can be useful for you.

  • Related