const player = (name, symbol) => {
return { name, symbol };
};
const Player1 = player("Player1", "X");
const Player2 = player("Player2", "O");
console.log(Player1);
for (i = 0; i < 9; i++) {
const getBoard = document.getElementById("board");
const createBoard = document.createElement("div");
getBoard.appendChild(createBoard);
createBoard.className = "game-board";
}
function createPItem(name) {
let p = document.createElement("p");
p.textContent = name;
p.className = "text";
return p;
}
const board = document.querySelector(".game-board");
board.addEventListener("click", selectBoard);
function selectBoard() {
board.appendChild(createPItem(`${Player1.symbol}`));
board.className = "complete-board";
}
body {
background-color: #fffdfa;
}
.title {
font-size: 42px;
font-family: "Dancing Script", cursive;
}
.player-turn {
font-size: 24px;
}
.content {
background-color: #fffdfa;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 700px;
width: 800px;
margin: 0 auto;
border-radius: 8px;
}
.board {
display: flex;
flex-flow: row wrap;
align-content: center;
justify-content: space-evenly;
gap: 10px;
background-color: #fff;
height: 500px;
width: 600px;
}
.board div,
.complete-board {
display: flex;
justify-content: center;
align-items: center;
border: 2px solid #000;
background-color: #3c4048;
width: 175px;
height: 150px;
}
.board div:hover {
background-color: #f4e06d;
transform: scale(1.1);
transition: 0.8s;
box-shadow: 5px 5px 0 rgba(0, 0, 0, 0.5);
}
.complete-board {
background-color: #f4e06d !important;
}
.text {
font-size: 64px;
}
.btn {
display: inline-block;
background-color: #4649ff;
padding: 0.5em 2em;
margin-top: 20px;
cursor: pointer;
font-family: "Poor Story", cursive;
font-size: 2rem;
letter-spacing: 0.4rem;
transition: all 0.3s;
text-decoration: none;
}
.btn:hover {
box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.5);
}
.parallelogram {
transform: skew(-20deg);
}
.skew-fix {
display: inline-block;
transform: skew(20deg);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="styles.css" />
<title>Tic Tac Toe</title>
</head>
<body>
<div class="content">
<p class="title">Tic Tac Toe</p>
<p class="player-turn">Player X turn</p>
<div id="board" class="board"></div>
<a id="btn" class="btn parallelogram">
<span class="skew-fix">Reset ></span>
</a>
</div>
<script src="app.js"></script>
</body>
</html>
I’m making Tic Tac Toe and I have a function that creates two players, assigning a symbol to each of them.
const player = (name, symbol) => {
return { name, symbol };
};
const Player1 = player("Player1", "X");
const Player2 = player("Player2", "O");
I also have this HTML which creates a board
<div class="content">
<p class="title">Tic Tac Toe</p>
<p class="player-turn">Player X turn</p>
<div id="board" class="board"></div>
</div>
and using a combination of display: flex and this for loop I create 9 divs that fit perfectly inside the game board.
for (i = 0; i < 9; i++) {
const getBoard = document.getElementById("board");
const createBoard = document.createElement("div");
getBoard.appendChild(createBoard);
createBoard.className = "game-board";
}
I have a function that creates a p element & assigns a class to it to get the proper font-size.
function createPItem(name) {
let p = document.createElement("p");
p.textContent = name;
p.className = "text";
return p;
}
And finally an eventListener that selects the gameBoard class that I click on and adds some text.
const board = document.querySelector(".game-board");
board.addEventListener("click", selectBoard);
function selectBoard() {
board.appendChild(createPItem(`${Player1.symbol}`));
board.className = "complete-board";
}
When I click the first div inside my board class, the above code works perfect and creates / assigns the p tag. Inside the p tag is the letter "X" which is what I want to happen. But when I click on any other div, nothing happens and I don’t know why.
What I’ve tried
I’ve tried a combination of several different things, including changing the for loop to give each div a class name like board${i} but not only does that seem tacky, it didn’t actually work and instead filled in every divs textContent all at once.
>Solution :
The issue is because you use querySelector(".game-board"), which will only select the first .game-board element. You need to use querySelectorAll() to find all elements with that class, and then loop over them to add the event handler.
In addition the selectBoard() function needs to be amended to accept the Event object as an argument so you can get a reference to the clicked element without relying on global variables:
const board = document.querySelectorAll(".game-board");
board.forEach(el => el.addEventListener("click", selectBoard));
function selectBoard(e) {
e.target.appendChild(createPItem(`${Player1.symbol}`));
e.target.className = "complete-board";
}
Here’s a full working version:
const player = (name, symbol) => ({ name, symbol });
const Player1 = player("Player1", "X");
const Player2 = player("Player2", "O");
for (i = 0; i < 9; i++) {
const getBoard = document.querySelector("#board");
const createBoard = document.createElement("div");
getBoard.appendChild(createBoard);
createBoard.className = "game-board";
}
function createPItem(name) {
let p = document.createElement("p");
p.textContent = name;
p.className = "text";
return p;
}
const board = document.querySelectorAll(".game-board");
board.forEach(el => el.addEventListener("click", selectBoard));
function selectBoard(e) {
e.target.appendChild(createPItem(`${Player1.symbol}`));
e.target.className = "complete-board";
e.target.removeEventListener('click', selectBoard); // prevent additional clicks
}
#board {
display: flex;
flex-wrap: wrap;
width: 150px;
border: 1px solid #000;
}
#board .game-board,
#board .complete-board {
flex: 1 1 30%;
border: 1px solid #000;
height: 50px;
}
#board .complete-board {
background-color: #CCC;
text-align: center;
}
<div id="board" class="board"></div>