简体   繁体   中英

How to make a loop wait for an event listener?

I am trying to create a coin toss game where you set the number of games you want to play, and then choose head or tails for each iteration. But my for loop doesen't wait for the eventListener and the loop is over before the user even clicked once.

function play(){
    head.addEventListener("click", choice);
    tails.addEventListener("click", choice);
}
function choice(e){
    let random = Math.floor(Math.random() *2);
    console.log(random);
    let clicked = e.target;
    e.target.style.border = "3px solid green";
    head.removeEventListener("click", choice);
    tails.removeEventListener("click", choice);
    if (random == 0){
        result.src = head.src;
        result.style.height = "100%";
        if(result.src == clicked.src){
            result.style.border = "3px solid green";
            
        }
        else{
            result.style.border = "3px solid red";
            
        }
    }
    if (random == 1){
        result.src = tails.src;
        result.style.height = "100%";
        if(result.src == clicked.src){
            result.style.border = "3px solid green";
            
        }
        else{
            result.style.border = "3px solid red";
            
        }
    }
    setTimeout(refresh, 3000);
    function refresh(){
        result.style.border = "none";
        clicked.style.border = "none";
    }

}

function wait(){
for (let i = 0; i < playAmount; i++){
    console.log(i);
    play();
}
}
wait();

Thank you in advance!

You can solve this problem without for loop. Just take a variable count = 0 and flag = false at the starting. Now just follow the program as under

var count = 0 , flag = true ;
    flag&&head.addEventListener("click", choice);
    flag&&tails.addEventListener("click", choice);
function choice(e){
    if(count>=playAmount)flag=false;
    else count++;
    let random = Math.floor(Math.random() *2);
    console.log(random);
    let clicked = e.target;
    e.target.style.border = "3px solid green";
    head.removeEventListener("click", choice);
    tails.removeEventListener("click", choice);
    if (random == 0){
        result.src = head.src;
        result.style.height = "100%";
        if(result.src == clicked.src){
            result.style.border = "3px solid green";
            
        }
        else{
            result.style.border = "3px solid red";
            
        }
    }
    if (random == 1){
        result.src = tails.src;
        result.style.height = "100%";
        if(result.src == clicked.src){
            result.style.border = "3px solid green";
            
        }
        else{
            result.style.border = "3px solid red";
            
        }
    }
    setTimeout(refresh, 3000);
    function refresh(){
        result.style.border = "none";
        clicked.style.border = "none";
    }

}

I hope this solves your problem.

Let us go through some key parts of your implementation(refer to my comments inline)

function play() { 
  head.addEventListener("click", choice);
  tails.addEventListener("click", choice);
  
  //the above 2 lines add a click event listener to the two buttons,
  //that is, whenever these 2 buttons are clicked,
  //the function `choice` will be called
}
function choice(e) {
  let random = Math.floor(Math.random() * 2);
  console.log(random);
  let clicked = e.target;
  e.target.style.border = "3px solid green";
  head.removeEventListener("click", choice);
  tails.removeEventListener("click", choice);
  
  //the above 2 lines remove the click event listener from the two buttons
  //that is, now the function `choice` will not be called at button click 
  
  if (random == 0) {
    result.src = head.src;
    result.style.height = "100%";
    if (result.src == clicked.src) {
      result.style.border = "3px solid green";
    } else {
      result.style.border = "3px solid red";
    }
  }
  if (random == 1) {
    result.src = tails.src;
    result.style.height = "100%";
    if (result.src == clicked.src) {
      result.style.border = "3px solid green";
    } else {
      result.style.border = "3px solid red";
    }
  }
  setTimeout(refresh, 3000);
  function refresh() {
    result.style.border = "none";
    clicked.style.border = "none";
  }
}

function wait() {
  for (let i = 0; i < playAmount; i++) {
    console.log(i);
    play();
    //calls the play function `playAmount` times
  }
}
wait();

Now let us discuss the problems with this approach

  1. Calling the play() function playAmount times from wait() (tries to) binds(adds) the click event listener to both the buttons playAmount times, but adding the same function n times as an event listener is same as adding it once, reference: addEventListener docs
  2. once choice is called, you remove the event listeners from both the buttons (remember, the event listeners were only bound once in a loop in the wait() function), now with no event listener bound on the buttons, the buttons wont register the event click anymore.

The below implementation should work for you:

let numberOfTurnsTaken = 0;
//add a global variable to count the turns taken

function play() { 
  head.addEventListener("click", choice);
  tails.addEventListener("click", choice);
  //bind the event listeners
}
function choice(e) {
  numberOfTurnsTaken++;
  //increment the turns
  let random = Math.floor(Math.random() * 2);
  console.log(random);
  let clicked = e.target;
  e.target.style.border = "3px solid green";

  //remove the event listeners only when the turns are over and we are `handling` the last turn
  if(numberOfTurnsTaken == playAmount){
    head.removeEventListener("click", choice);
    tails.removeEventListener("click", choice);
  }
  
  if (random == 0) {
    result.src = head.src;
    result.style.height = "100%";
    if (result.src == clicked.src) {
      result.style.border = "3px solid green";
    } else {
      result.style.border = "3px solid red";
    }
  }
  if (random == 1) {
    result.src = tails.src;
    result.style.height = "100%";
    if (result.src == clicked.src) {
      result.style.border = "3px solid green";
    } else {
      result.style.border = "3px solid red";
    }
  }
  setTimeout(refresh, 3000);
  function refresh() {
    result.style.border = "none";
    clicked.style.border = "none";
  }
}

//set things rolling by binding click event handlers on the buttons
play();


//the loop is no longer needed
//function wait() {
//  for (let i = 0; i < playAmount; i++) {
//    console.log(i);
//    play();
//  }
//}
//wait();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM