Je fais un simple jeu de cartes à retournement qui verrouille les cartes en position de retournement si les deux cartes correspondent et les remet en position de repos si elles ne correspondent pas. Lorsque la première paire de cartes est retournée, qu'il s'agisse d'un match ou non, le jeu fonctionne correctement. Le problème est que lorsque je clique sur une troisième carte, la console renvoie l'erreur:

"Uncaught TypeError: Impossible de lire la propriété 'dataset' de null à checkForMatch à HTMLDivElement.flipCard"

Comment pourrais-je résoudre ce problème?

// * Declaring Varaibles
// Get cards on the board
const cards = document.querySelectorAll(".card");
let isCardFlipped = false;
let lockBoard = false;
let firstCard, secondCard;

// * Functions
// Flips cards over
function flipCard() {
  if (lockBoard) return;
  if (this === firstCard) return;

  // Adding class name "flip" to all HTML elments with the class name "card"
  this.style.transform = "rotateY(180deg)";

  if (!isCardFlipped) {
    isCardFlipped = true;
    firstCard = this;

    return;
  }

  secondCard = this;
  checkForMatch();
}

// Checks to see if the cards match
function checkForMatch() {
  let isMatch = firstCard.dataset.monke === secondCard.dataset.monke;

  // isMatch ? disableCards() : unflipCards();

  if (isMatch) {
    disableCards();
  }
  else {
    unflipCards();
  }
}

// Locks the cards in place if they match
function disableCards() {
  firstCard.removeEventListener("click", flipCard);
  secondCard.removeEventListener("click", flipCard);

  resetBoard();
}

// Flips the cards back over if they don't match
function unflipCards() {
  lockBoard = true;

  setTimeout(() => {
    firstCard.style.transform = "";
    secondCard.style.transform = "";

    resetBoard();
  }, 1000);

}

// Resets the board
function resetBoard() {
  [hasFlippedCard, lockBoard] = [false, false];
  [firstCard, secondCard] = [null, null];
}

// * Event Listeners
// Event listener for all the cards
cards.forEach((item) => {
  item.addEventListener("click", flipCard);
});
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: "Londrina Solid", cursive;
}

body {
    background: linear-gradient(180deg, rgb(34, 179, 34), rgb(163, 126, 57));
    height: 100vh;
}

.container {
    padding: 1rem;
    width: 100%;
    height: 100%;
}

h1 {
    text-align: center;
    margin-bottom: 2rem;
    font-size: 3rem;
    color: #000;
}

.row {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    margin: 2rem;
    padding-top: 1rem;
}

.card-container {
    position: relative;
    margin: auto;
    width: 150px;
    height: 200px;
}

.card {
    position: absolute;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
    transition: transform 1s ease;
}

.front-face {
    position: absolute;
    backface-visibility: hidden;
    height: 100%;
    width: 100%;
    background: rgb(244, 238, 86);
    border-radius: 10px;
}

.back-face {
    position: absolute;
    backface-visibility: hidden;
    transform: rotateY(180deg);
}

.pic-container {
    height: 200px;
    width: 150px;
}

img {
    height: 100%;
    width: 100%;
    border-radius: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="preconnect" href="https://fonts.gstatic.com">
  <link href="https://fonts.googleapis.com/css2?family=Londrina+Solid&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="style.css">
  <title>Matching Game</title>
</head>
<body>
  <div class="container">
    <h1>Monke Matching Game</h1>
    <div class="row">
      <div class="card-container">
        <div class="card" data-monke="gorilla">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke1.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
      <div class="card-container">
        <div class="card" data-monke="gorilla">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke1.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
      <div class="card-container">
        <div class="card" data-monke="chimp">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke2.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="card-container">
        <div class="card" data-monke="chimp">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke2.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
      <div class="card-container">
        <div class="card" data-monke="baby">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke3.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
      <div class="card-container">
        <div class="card" data-monke="baby">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke3.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>


  <script src="app.js"></script>
</body>
</html>
2
Zanto 25 févr. 2021 à 02:54

2 réponses

Meilleure réponse

Vous oubliez de définir isCardFlipped sur false après avoir retourné des cartes ou désactivé des cartes.

// * Declaring Varaibles
// Get cards on the board
const cards = document.querySelectorAll(".card");
let isCardFlipped = false;
let lockBoard = false;
let firstCard, secondCard;

// * Functions
// Flips cards over
function flipCard() {
  if (lockBoard) return;
  if (this === firstCard) return;

  // Adding class name "flip" to all HTML elments with the class name "card"
  this.style.transform = "rotateY(180deg)";

  if (!isCardFlipped) {
    isCardFlipped = true;
    firstCard = this;

    return;
  }

  secondCard = this;
  checkForMatch();
}

// Checks to see if the cards match
function checkForMatch() {
  let isMatch = firstCard.dataset.monke === secondCard.dataset.monke;
  // isMatch ? disableCards() : unflipCards();

  if (isMatch) {
    disableCards();
  }
  else {
    unflipCards();
  }
}

// Locks the cards in place if they match
function disableCards() {
  firstCard.removeEventListener("click", flipCard);
  secondCard.removeEventListener("click", flipCard);
  isCardFlipped = false;
  resetBoard();
}

// Flips the cards back over if they don't match
function unflipCards() {
  lockBoard = true;
  isCardFlipped = false;
  setTimeout(() => {
    firstCard.style.transform = "";
    secondCard.style.transform = "";

    resetBoard();
  }, 1000);

}

// Resets the board
function resetBoard() {
  [hasFlippedCard, lockBoard] = [false, false];
  [firstCard, secondCard] = [null, null];
}

// * Event Listeners
// Event listener for all the cards
cards.forEach((item) => {
  item.addEventListener("click", flipCard);
});
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: "Londrina Solid", cursive;
}

body {
    background: linear-gradient(180deg, rgb(34, 179, 34), rgb(163, 126, 57));
    height: 100vh;
}

.container {
    padding: 1rem;
    width: 100%;
    height: 100%;
}

h1 {
    text-align: center;
    margin-bottom: 2rem;
    font-size: 3rem;
    color: #000;
}

.row {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    margin: 2rem;
    padding-top: 1rem;
}

.card-container {
    position: relative;
    margin: auto;
    width: 150px;
    height: 200px;
}

.card {
    position: absolute;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
    transition: transform 1s ease;
}

.front-face {
    position: absolute;
    backface-visibility: hidden;
    height: 100%;
    width: 100%;
    background: rgb(244, 238, 86);
    border-radius: 10px;
}

.back-face {
    position: absolute;
    backface-visibility: hidden;
    transform: rotateY(180deg);
}

.pic-container {
    height: 200px;
    width: 150px;
}

img {
    height: 100%;
    width: 100%;
    border-radius: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="preconnect" href="https://fonts.gstatic.com">
  <link href="https://fonts.googleapis.com/css2?family=Londrina+Solid&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="style.css">
  <title>Matching Game</title>
</head>
<body>
  <div class="container">
    <h1>Monke Matching Game</h1>
    <div class="row">
      <div class="card-container">
        <div class="card" data-monke="gorilla">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke1.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
      <div class="card-container">
        <div class="card" data-monke="gorilla">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke1.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
      <div class="card-container">
        <div class="card" data-monke="chimp">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke2.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="row">
      <div class="card-container">
        <div class="card" data-monke="chimp">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke2.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
      <div class="card-container">
        <div class="card" data-monke="baby">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke3.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
      <div class="card-container">
        <div class="card" data-monke="baby">
          <div class="front-face">
            <img src="img/Banna-cartoon.png" alt="">
          </div>
          <div class="back-face">
            <div class="pic-container">
              <img src="img/monke3.jpg" alt="">
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>


  <script src="app.js"></script>
</body>
</html>
2
maziyank 25 févr. 2021 à 00:19

Le jeu de société est réinitialisé après l'événement onclick, il appelle cette fonction resetBoard() et définit les variables firstCard sur null. Lors de l'événement suivant, la variable est null.

Supprimer cette ligne

// Resets the board
function resetBoard() {
  [hasFlippedCard, lockBoard] = [false, false];
  //[firstCard, secondCard] = [null, null];
}
2
jTorleon 25 févr. 2021 à 00:42