0

As the following code, when I click the "play round" button, it add an click event listener for each three options: Rock, Paper and Scissors. When they are ready, they turn to yellow.

When player pick one of them, the event listener need to be removed (prevent from miss click again).

According to this answer Removing an anonymous event listener, I store the event handler reference when creating the event listener. It doesn't work. In the following code, we still can pick all three options.

const playerSelection = function(selected, selections) {
    selected.id = 'selected';
    selections.forEach((selection) => {
        selection.classList.remove('listening');
        // get the anonymous event handler by cached reference
        selection.removeEventListener('click', selection.clickHandler, false);
    }); 
}

const playRound = function() {
    const selections = document.querySelectorAll(".selection");
    selections.forEach((selection) => {
        selection.id = undefined;
        selection.classList.add('listening');
        selection.addEventListener('click', function clicked() {
            // trying to store the reference of event handler
            selection.clickHandler = clicked; 
            playerSelection(selection, selections);
        }, false);
    });
};

const round = document.querySelector(".round");
round.addEventListener('click', playRound);
.selection,
.round {
    width: 100px;
    height: 50px;
    border: 1px solid black;
    background-color: white;
}

.selection.listening {
    background-color: yellow;
}

#selected {
    background-color: red;
}
    <div data-name="Rock" class="selection">Rock</div>
    <div data-name="Paper" class="selection">Paper</div>
    <div data-name="Scissors" class="selection">Scissors</div>
    <div class="round">Play a round</div>

The event listener was not removed. Debugging tool showed the selection.clickHandler property is undefined when playerSelection is called. enter image description here

enter image description here

When I go back to playRound function, I'm sure that selection.clickHandler attribute well setted. enter image description here

enter image description here

Anyone knows what's wrong?

VLAZ
  • 26,331
  • 9
  • 49
  • 67
shen
  • 933
  • 10
  • 19

1 Answers1

1

Just store your handler before adding the eventListener:

const playerSelection = function(selected, selections) {
    selected.id = 'selected';
    selections.forEach((selection) => {
        selection.classList.remove('listening');
        // get the anonymous event handler by cached reference
        selection.removeEventListener('click', selection.clickHandler, false);
    }); 
}

const playRound = function() {
    const selections = document.querySelectorAll(".selection");
    selections.forEach((selection) => {
        selection.id = undefined;
        selection.classList.add('listening');
        selection.clickHandler = function() {
            playerSelection(selection, selections);
        }
        selection.addEventListener('click', selection.clickHandler, false);
    });
};

const round = document.querySelector(".round");
round.addEventListener('click', playRound);
.selection,
.round {
    width: 100px;
    height: 50px;
    border: 1px solid black;
    background-color: white;
}

.selection.listening {
    background-color: yellow;
}

#selected {
    background-color: red;
}
<div data-name="Rock" class="selection">Rock</div>
    <div data-name="Paper" class="selection">Paper</div>
    <div data-name="Scissors" class="selection">Scissors</div>
    <div class="round">Play a round</div>
Kosh
  • 16,966
  • 2
  • 19
  • 34
  • it works. I wonder what's the difference between "store before" and "store after". Why the reference is not stored if I save it after adding the event listener. – shen Feb 04 '22 at 20:35
  • 1
    @shen, when you're trying to store `clicked` within itself, it's not visible from within and you're getting undefined as `clicked` is not defined in the function's scope. – Kosh Feb 04 '22 at 20:41
  • thx. really helpful :) – shen Feb 04 '22 at 20:48