How do I make animation play after each ‘game over/restart’ status and not only once(as showin in my code below)?

My code only animates once after first ‘game over’ and ‘reset’ status. But after each next status change, animation(s) does/do not play again. I want to know if there is something wrong in my code, or there is a thing(s) to add/I omitted something? I provide you with my CSS/VanillaJS code below.

VanillaJS =>

const choices = document.querySelectorAll(".option");
const playerScoreElement = document.querySelector(".player-score");
const computerScoreElement = document.querySelector(".computer-score");
const chooseMove = document.querySelector(".choose-move");
const movesLeft = document.querySelector(".moves-left p");
const result = document.querySelector(".result");
const resetBtn = document.querySelector(".reset");
const modal = document.querySelector(".modal");
const optionsElement = document.querySelector(".options");
const mainHeaderElement = document.querySelector("h1");

let playerScore = 0;
let computerScore = 0;
let moves = 0;

const game = () => {
    choices.forEach(choice => {
        choice.addEventListener("click", () => {
            moves++;
            if (moves === 10) {
                gameOver();
            } else if(moves > 10) {
               
                return;
            } 
            // console.log(moves);
            movesLeft.textContent = `Moves Left: ${10 - moves}`;


            const playerChoice = choice.getAttribute(['data-choice']); // player choice
            const computerChoices = ['rock', 'paper', 'scissors'];
            const choiceIndex = Math.floor(Math.random() * 3);
            const computerChoice = computerChoices[choiceIndex]; // computer choice
            determineWinner(playerChoice, computerChoice);

        })
    })

    resetBtn.addEventListener("click", resetGame);
};

const determineWinner = (playerChoice, computerChoice) => {
    if (playerChoice === "rock" && computerChoice === "scissors" ||
        playerChoice === "scissors" && computerChoice === "paper" ||
        playerChoice === "paper" && computerChoice === "rock"
    ) {
        playerScore++;
        playerScoreElement.textContent = playerScore;
        result.textContent = "You win a point!";
    } else if (playerChoice === computerChoice) {
        result.textContent = "A Draw!";
    } else {
        computerScore++;
        computerScoreElement.textContent = computerScore;
        result.textContent = "Computer wins a point!";
    }
}

const gameOver = () => {
    const finalResult = playerScore === computerScore ? "Game Over! It's a draw!" :
                        playerScore > computerScore ? "Game Over! You have won!" :
                        "Game Over! Computer has won!"

    chooseMove.textContent = finalResult;
    chooseMove.style.marginTop = "1em";
    chooseMove.style.transition = "all 500ms ease-in-out";
    chooseMove.style.transform = "scale(1.02)";
    chooseMove.style.color = "red";
    chooseMove.style.fontSize = "2rem";
    result.textContent = "";
    resetBtn.style.display = "block";
    resetBtn.textContent="Reset Game";
    mainHeaderElement.style.opacity = "0";
    modal.setAttribute("open", "");
    movesLeft.style.display = "none";
    optionsElement.style.display = "none";
    result.style.display = "none";
    
    return;
}

const resetGame = () => {
    moves = 0;
    playerScore = 0;
    computerScore = 0;
    playerScoreElement.textContent = playerScore;
    computerScoreElement.textContent = computerScore;
    chooseMove.textContent = "Choose your move!";
    movesLeft.style.display = "block";
    movesLeft.textContent = `Moves Left: 10`;
    result.textContent = "";
    resetBtn.style.display = "none";
    mainHeaderElement.style.opacity = "1";
    modal.setAttribute("close", "");
    optionsElement.style.display = "flex";
    result.style.display = "flex";
}

game();

CSS =>

.modal {
    position: fixed;
    background: rgb(255, 252, 252);
    box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
    color: white;
    top: 20%;
    left: 50%;
    transform: translateX(-50%);
    text-align: center;
    font-size: 2rem;
    padding: 0.5em;
    width: 30em;
    border-radius: 2px;
    opacity: 0;
    pointer-events: none;
    z-index: 1;
}

.modal p {
    color: red;
}

.modal[open] {
    animation: modal-fade-in 500ms;
    animation-fill-mode: forwards;
}

.modal[close] {
    animation: modal-fade-out 500ms;
    animation-fill-mode: forwards;
}


/* MODAL WINDOW ANIMATIONS */
@keyframes modal-fade-in {
    0% {
        display: none;
        opacity: 0;
    }
    1% {
        display: block;
    }
    100% {
        display: block;
        opacity: 1;
    }
}

@keyframes modal-fade-out {
    0% {
        display: block;
        opacity: 1;
    }
    99% {
        display: block;
    }
    100% {
        display: none;
        opacity: 0;
    }
}

  • Thank you for your suggestions, they have been most helpful! I decided to use solution which includes removing corresponding attribute in each function before adding another one.

    – 

When you set the attribute “open” and then set the attribute “close”, the resulting modal has both “open” and “close” attributes set so it is essentially getting confused because both are applied after you close it for the first time.

there are a handful of ways to handle this, you can make separate open and close classes and toggle them on and off like the below example, you could set the attribute like this setAttribute(‘data-modal’,’open’) and setAttribute(‘data-modal’,’close’) and adjust the selectors accordingly, this way when you set the attribute its actually changing it from open to closed not setting separate attributes, or you could toggle a single class on and off and not use a keyframe animation but instead use a css transition (display isn’t a animatable property, so it would only transition opacity, and since you are preventing click events it should be fine when hidden)

Also check out the html dialog element. It probably wont help much since you already made your own and it doesn’t animate by default, but it can save you some time if you figure it out. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog

document.querySelector('#open').onclick = function() {
  document.querySelector('#workingModal').classList.remove('close');
  document.querySelector('#workingModal').classList.add('open');
  document.querySelector('#notWorking').setAttribute('open','');
}

document.querySelector('#close').onclick = function() {
  document.querySelector('#workingModal').classList.remove('open');
  document.querySelector('#workingModal').classList.add('close');
  document.querySelector('#notWorking').setAttribute('close','');
}
.modal {
    position: fixed;
    background: rgb(255, 252, 252);
    box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
    color: blue;
    top: 20%;
    left: 50%;
    transform: translateX(-50%);
    text-align: center;
    font-size: 2rem;
    padding: 0.5em;
    width: 30em;
    border-radius: 2px;
    opacity: 0;
    pointer-events: none;
    z-index: 1;
}

.modal[open] {
    animation: modal-fade-in 500ms;
    animation-fill-mode: forwards;
}

.modal[close] {
    animation: modal-fade-out 500ms;
    animation-fill-mode: forwards;
}

.modal.open {
    animation: modal-fade-in 500ms;
    animation-fill-mode: forwards;
}

.modal.close {
    animation: modal-fade-out 500ms;
    animation-fill-mode: forwards;
}

/* MODAL WINDOW ANIMATIONS */
@keyframes modal-fade-in {
    0% {
        display: none;
        opacity: 0;
    }
    1% {
        display: block;
    }
    100% {
        display: block;
        opacity: 1;
    }
}

@keyframes modal-fade-out {
    0% {
        display: block;
        opacity: 1;
    }
    99% {
        display: block;
    }
    100% {
        display: none;
        opacity: 0;
    }
}
<button id="open">open</button>
<button id="close">close</button>

<div class="modal" id="workingModal">
  I animate
</div>

<div class="modal" id="notWorking" style="top:40%;">
  I don't animate
</div>

Leave a Comment