I need to make a pexeso game as my homework to school. I have basically implemented the whole game, but I am stuck at setTimeout issue.
This is the main logic of the game:
let firstCard = null;
let secondCard = null;
let points = 0;
let turnedCards = 0;
const createCard = (cityName) => {
const card = document.createElement('div');
card.classList.add('card');
card.innerText = cityName;
card.addEventListener('click', () => {
if (firstCard == null) {
firstCard = card;
card.classList.add('revealed');
} else if (secondCard == null) {
secondCard = card;
card.classList.add('revealed');
if (firstCard.innerText == secondCard.innerText && firstCard != secondCard && !firstCard.classList.contains('final') && !secondCard.classList.contains('final')) {
updateScore();
firstCard.classList.add('final');
secondCard.classList.add('final');
} else {
setTimeout(() => {
if (!firstCard.classList.contains('final')) {
firstCard.classList.remove('revealed');
}
if (!secondCard.classList.contains('final')) {
secondCard.classList.remove('revealed');
}
},2000);
}
firstCard = null;
secondCard = null;
}
});
gameArea.appendChild(card);
}
the setTimeout method is there to provide you some time to see turned cards. Now, when I start this game, I always get
main.js:38 Uncaught TypeError: Cannot read properties of null (reading 'classList')
Which come from the firstCard.classList and secondCard.classList in the setTimeout method. I mean, how can firstCard and secondCard be null, if i explicitly assigned value to them just before the method executed?
Any help appreciated :)
As pointed out in a comment, the error is most likely due by the assignments
firstCard = null;
secondCard = null;
which run before the setTimeout callback. In fact, the callback runs with 2000ms delay, so most likely after that assignment has been executed.
I am not sure if this will break the logic of the game, but a solution might be to move these assignments inside the setTimeout callback itself (as well as in the "then" branch of the larger if block).
if (firstCard.innerText == secondCard.innerText && firstCard != secondCard && !firstCard.classList.contains('final') && !secondCard.classList.contains('final')) {
updateScore();
firstCard.classList.add('final');
secondCard.classList.add('final');
firstCard = null;
secondCard = null;
} else {
setTimeout(() => {
if (!firstCard.classList.contains('final')) {
firstCard.classList.remove('revealed');
}
if (!secondCard.classList.contains('final')) {
secondCard.classList.remove('revealed');
}
firstCard = null;
secondCard = null;
},2000);
}
Mozilla's guide to setTimeout might be a good resource to help with this issue:
https://developer.mozilla.org/en-US/docs/Web/API/setTimeout