This is a bit of a challenge !!! I know there are many such questions asked before but all of them are for specific cases.
I am creating a tictactoe game using module design pattern. I'm using the function below to create two function which renders X & O and it also appends them to the dom. The gameFlow function is in a setInterval so whenever players click on the dom, x & o are rendered. The function also gets the board from the gameBoard module ( which is also below ) and then adds X & O in the board.
const gameFlow = () => {
const board = gameBoard.getBoard()
const box = document.querySelectorAll('.gameBox')
let x = true // Put this in the global scope if there is an error.
const renderX = (e) => {
for (let i = 0; i < board.length; i ) {
const target = e.target
const data = target.getAttribute('data-index')
const el = document.createElement('p')
el.classList.add('elstyle')
if (board[i] === '') {
if (i === Number(data)) {
gameBoard.fillBoard(i, 1, '❌')
el.textContent = `${board[i]}`
target.appendChild(el)
x = false
}
}
}
}
const renderO = (e) => {
for (let i = 0; i < board.length; i ) {
const target = e.target
const data = target.getAttribute('data-index')
const el = document.createElement('p')
el.classList.add('elstyle')
if (board[i] === '') {
if (i === Number(data)) {
gameBoard.fillBoard(i, 1, '⭕')
el.textContent = `${board[i]}`
target.appendChild(el)
x = true
}
}
}
}
box.forEach(el => el.addEventListener('click', ((e) => {
if (x) {
renderX(e)
} else {
renderO(e)
}
})))
}
Below is the gameBoard module. As shown in the gameFlow function, the 2 functions in gameBoard also fills the board array. Xs & Os are then rendered to the dom by iterating through the board array.
const gameBoard = (() => {
let board = [
'', '', '',
'', '', '',
'', '', ''
]
const getBoard = () => {
return board
}
const fillBoard = (index, count, el) => {
board.splice(index, count, el)
}
const resetBoard = () => {
board.splice(0, board.length)
}
const setBoard = () => {
board = [
'', '', '',
'', '', '',
'', '', ''
]
}
return {getBoard, fillBoard, resetBoard, setBoard}
})()
And finally, below is the restart module where the error is logged from.
const restartGame = (() => {
const mainThree = document.getElementById('mainThree')
const restart = document.getElementById('restartBtn')
const boxes = document.querySelectorAll('.gameBox')
restart.addEventListener('click', () => {
mainThree.style.display = 'none'
// gameBoard.resetBoard()
gameBoard.setBoard()
boxes.forEach(el => el.removeChild(el.firstChild))
})
})()
So, whenever I restart the game, the elements in the dom (Xs and Os) are cleared from the dom (but the error is logged in the console). But when I play again and after I restart, the elements are cleared or some elements are cleared (deleted) while some are not.
here is the link to the full app.js file. [enter link description here][1] [1]: https://github.com/rabtennamgyal/TOP-Project-tictactoe/blob/main/app.js
Thanks for all the help.
Blockquote
CodePudding user response:
In your restart code, boxes.forEach(el => el.removeChild(el.firstChild))
is called for each element with class gameBox
. However, only some of these elements have children (the X's and O's played during the game)> So in some cases, el.firstChild
is null
. Therefore, you're attempting to call el.removeChild(null)
, which is throwing the error because null
is not a node. To fix this, you should check if el.firstChild exists, and only call removeChild if it's not null.
CodePudding user response:
Thank you both for helping me out. I solved it with creating a new function which deletes every dom element. I think the error was that with every game played, Xs and Os are appended into the dom and since Xs and Os can be played into different boxes during different game plays; some boxes contains two elements while others only one etc. So before I was deleting only the firstChild hence the error. I have to delete every child. To I'm using the code
for (let i = 0; i < boxes.length; i ) {
while (boxes[i].firstChild) {
boxes[i].removeChild(boxes[i].firstChild);
}
}
const restartGame = (() => {
const mainThree = document.getElementById('mainThree')
const restart = document.getElementById('restartBtn')
const boxes = document.querySelectorAll('.gameBox')
function goAgain() {
mainThree.style.display = 'none'
// gameBoard.resetBoard()
gameBoard.setBoard()
for (let i = 0; i < boxes.length; i ) {
while (boxes[i].firstChild) {
boxes[i].removeChild(boxes[i].firstChild);
}
}
}
restart.addEventListener('click', goAgain)
})()
Thank you both for your help. Peace