javascriptremoveeventlistener

Why can't I add or remove event listeners in JavaScript


I am making a basic rock paper scissors game. I am making it so when you hover over an option it rises, and when you click it, it should stay in the air, but I am unable to remove the event listener.

<main>
    <h2>Choose A Play:</h2>

    <div id="rock" onmouseover="hover('rock')" onmouseout="out('rock')" onclick="select('rock')">
        Rock
    </div>

    <div id="paper" onmouseover="hover('paper')" onmouseout="out('paper')" onclick="select('paper')">
        Paper
    </div>

    <div id="scissors" onmouseover="hover('scissors')" onmouseout="out('scissors')" onclick="select('scissors')">
        Scissors
    </div>


</main>
#rock {
  background-color: #252422;

  font-size: 25px;
  text-align: center;
  color: #fffcf2;

  height: 100px;
  width: 200px;

  padding: 25px;
  margin-left: 50px;
  margin-top: 50px;

  float: left;
}

#paper {
  background-color: #252422;

  font-size: 25px;
  text-align: center;
  color: #fffcf2;

  height: 100px;
  width: 200px;

  padding: 25px;
  margin-left: 50px;
  margin-top: 50px;

  float: left;
}

#scissors {
  background-color: #252422;

  font-size: 25px;
  text-align: center;
  color: #fffcf2;

  height: 100px;
  width: 200px;

  padding: 25px;
  margin-top: 50px;
  margin-right: 50px;

  float: right;
}
let options = ['rock', 'paper', 'scissors'];


function hover(elementId) {
    document.getElementById(elementId).style.marginTop = '10px';
}

function out(elementId) {
    document.getElementById(elementId).style.marginTop = '50px';
}

function select(elementId) {
    document.getElementById(elementId).style.backgroundColor = '#ffba08';
    document.getElementById(elementId).style.marginTop = '10px';

    let userChoice = options.filter(x => x === elementId);
    let userNoPick = options.filter(x => x !== elementId);
    revokeListeners(userChoice, userNoPick);
}

function revokeListeners(userSelection, userNoSelection) {

    document.getElementById(userSelection).removeEventListener('mouseout', out)
}

I didn't include all of the CSS so it looks a bit funky.

Expected: When a div is clicked it turns yellow then floats in the air.

Result: The event listener does not get deleted and the box drops again.


Solution

  • You can't remove an event listener with removeEventListener that was not added with addEventListener (https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener). That being said, don't remove something you might want later.

    I've used a data attribute to manage the selected state. Though another thing to consider would be using hiding radio buttons in label element, which is an inbuilt way of managing mutually exclusive selections

    I've also dropped inline listeners to a more modern approach

    let options = ['rock', 'paper', 'scissors'];
    
    //use the data attribute as a selector to add event listeners
    document.querySelectorAll('[data-status]').forEach(function(el){
      //Click
       el.addEventListener("click",function(){
        this.style.backgroundColor = '#ffba08';
        this.style.marginTop = '10px';
        this.dataset.status = "selected";
    
        let userChoice = options.filter(x => x === this.id);
        let userNoPick = options.filter(x => x !== this.id);
      });
      
    
      //Hover
      el.addEventListener("mouseover",function(){
        this.style.marginTop = '10px';
      });
      
      
      //Mouse out
        el.addEventListener("mouseout",function(){
        if(this.dataset.status !== "selected") {
          this.style.marginTop = '50px';
        }
      });
      
    });
    #rock {
      background-color: #252422;
    
      font-size: 25px;
      text-align: center;
      color: #fffcf2;
    
      height: 100px;
      width: 200px;
    
      padding: 25px;
      margin-left: 50px;
      margin-top: 50px;
    
      float: left;
    }
    
    #paper {
      background-color: #252422;
    
      font-size: 25px;
      text-align: center;
      color: #fffcf2;
    
      height: 100px;
      width: 200px;
    
      padding: 25px;
      margin-left: 50px;
      margin-top: 50px;
    
      float: left;
    }
    
    #scissors {
      background-color: #252422;
    
      font-size: 25px;
      text-align: center;
      color: #fffcf2;
    
      height: 100px;
      width: 200px;
    
      padding: 25px;
      margin-top: 50px;
      margin-right: 50px;
    
      float: right;
    }
    <main>
        <h2>Choose A Play:</h2>
    
        <div id="rock" data-status>
            Rock
        </div>
    
        <div id="paper" data-status>
            Paper
        </div>
    
        <div id="scissors" data-status>
            Scissors
        </div>
    
    
    </main>

    Or the HTML/CSS only approach, then you can leave JavaScript to handle the game logic. Leave the presentation to CSS

    label {
     background-color: #252422;
    
      font-size: 25px;
      text-align: center;
      color: #fffcf2;
    
      height: 100px;
      width: 200px;
    
      padding: 25px;
      margin-left: 50px;
      margin-top: 50px;
    
      float: left;
    }
    
    label:hover, label:has(:checked) {
      margin-top: 10px;
    }
    
    label:has(:checked) {
      background-color:#ffba08;
    }
    
    label > input {
      display:none;
    }
    
    #rock {
     /* background-color: #252422;
    
      font-size: 25px;
      text-align: center;
      color: #fffcf2;
    
      height: 100px;
      width: 200px;
    
      padding: 25px;
      margin-left: 50px;
      margin-top: 50px;
    
      float: left;*/
    }
    
    #paper {
      /*background-color: #252422;
    
      font-size: 25px;
      text-align: center;
      color: #fffcf2;
    
      height: 100px;
      width: 200px;
    
      padding: 25px;
      margin-left: 50px;
      margin-top: 50px;
    
      float: left;*/
    }
    
    #scissors {
     /* background-color: #252422;
    
      font-size: 25px;
      text-align: center;
      color: #fffcf2;
    
      height: 100px;
      width: 200px;
    
      padding: 25px;
      margin-top: 50px;
      margin-right: 50px;*/
    
      float: right;
    }
    <main>
        <h2>Choose A Play:</h2>
    
        <label id="rock">
            Rock
            <input type="radio" name="game" value="rock">
        </label>
    
        <label id="paper">
            Paper
            <input type="radio" name="game" value="paper">
        </label>
    
        <label id="scissors">
            Scissors
            <input type="radio" name="game" value="scissors">
        </label>
    
    
    </main>