I'm making a Tic-Tac-Toe game. My problem is that my code allows to rewrite X or O even if one of the squares already contain X or O. I'm using an if statement to write either X or O depending on a number variable that increases by one every time. I would like to add another conditional that only allows X or O to be written if my tag is empty. How do i do this?. Note: Only javascript please, since I haven't started learning jQuery yet. Thanks a bunch in advance!
JS
var tds = document.querySelectorAll("td"); var player = 1; var str = ""; for (var i = 0; i < tds.length; i++) { tds[i].addEventListener("click", function(){ if( player % 2 === 0 && tds[i] !== "<td>X</td>" && tds[i] !== "<td>O</td>"){ this.textContent = "O"; } else if (player % 2 !== 0 && tds[i] === "" ) { this.textContent = "X"; } player++; }); } HTML -
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="css.css"> <title></title> </head> <body> <table> <tr> <td></td> <td></td> <td></td> </tr> <tr> <td></td> <td></td> <td></td> </tr> <tr> <td></td> <td></td> <td></td> </tr> </table> <script type="text/javascript" src="js.js"> </script> </body> </html> 16 Answers
You could just check the childNodes property of an element, which returns a Nodelist.
If it's length is 0, then your element is empty.
const elem = document.querySelector("#container") console.log(elem.childNodes.length)<div></div>Careful as line breaks count as text though.
node.childNodes.length will pick up spaces or other elements inside the node you're checking, to include any spacing or returns from formatting.
e.g. The following returns 3
<td> <!-- returns NodeList(3) [text, comment, text] --> </td> <span> <span> will result in 1 and <span> <span> </span></span> will result in 2 with the above method.
Unless you're sure of your data or cleansing your data source well, I'd use the following to test against node emptiness.
// <div /> function isEmpty(node) { return node.textContent.trim() === ""; } isEmpty(SomeElement); // or Element.prototype.isEmpty = function() { return this.textContent.trim() === ""; } SomeElement.isEmpty(); function emptyElementNode(node) { return node.textContent.trim() === ""; } var xo = TicTacToe.getElementsByTagName('div'); for (var i = 0; i < xo.length; ++i) { if (emptyElementNode(xo[i])) { xo[i].classList.add('highlight'); xo[i].textContent = "⚬"; } }#TicTacToe { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr); grid-gap: 0.063rem; width: 6.25rem; height: 6.25rem; align-items: center; justify-items: center; margin: -0.063rem; overflow: hidden; } #TicTacToe { display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr); grid-gap: 0.063rem; width: 6.25rem; height: 6.25rem; align-items: center; justify-items: center; margin: -0.063rem; overflow: hidden; } #TicTacToe div{ position: relative; } #TicTacToe div::before { content: ""; display: block; position: absolute; width: calc(6.25rem / 3); height: calc(6.25rem / 3); left: 50%; top: 50%; transform: translate3d(-50%, -50%, 0); background: #fff; z-index: -1; outline: 1px solid #222; } #TicTacToe .highlight::before { background: #ddd; } #TicTacToe div{ position: relative; } #TicTacToe div::before { content: ""; display: block; position: absolute; width: calc(6.25rem / 3); height: calc(6.25rem / 3); left: 50%; top: 50%; transform: translate3d(-50%, -50%, 0); background: #fff; z-index: -1; outline: 1px solid #222; } #TicTacToe .highlight::before { background: #ddd; }<div> <div>⚬</div> <div>×</div> <div>×</div> <div>⚬</div> <div>⚬</div> <div>×</div> <div></div> <div>×</div> <div>⚬</div> </div>0You can use innerHtml property to check if element contain anything. But I would prefer to add class marked when you set the html X or O. Then in your js check if the element has class marked. Add class on click event of td using:
function mark(e) { var isMarked = hasClass(e,"marked"); if(!isMarked ) { e.className+= " marked"; //add X or O } else { //do something else } function hasClass(element, className) { return element.className && new RegExp("(^|\\s)" + className + "(\\s|$)").test(element.className); } HTML:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="css.css"> <title></title> </head> <body> <table> <tr> <td onclick="mark(this)"></td> . . <td></td> </tr> </table> <script type="text/javascript" src="js.js"> </script> </body> </html> You can check the innerHTML property of your elements to ascertain if they contain anything- in your case X or O.
So, the condition should look like this.
if( player % 2 === 0 && tds[i].innerHTML !== "X" && tds[i].innerHTML !== "O") { } 1please find working solution below.
var player = 1; var blocks = document.querySelectorAll('td'); var title = document.getElementById('title'); function switchPlayer(currentPlayer) { if (currentPlayer === 1) { player = 2; title.innerHTML = 'Player: 2(O)' } else { player = 1; title.innerHTML = 'Player: 1(X)' } } blocks.forEach(function(block) { block.addEventListener('click', function() { if (!block.innerHTML) { if (player === 1) { block.innerHTML = 'X'; } else { block.innerHTML = 'O'; } switchPlayer(player) } }) });td { border: 1px solid black; width: 50px; height: 50px; }<h1> Player: 1 (X) </h1> <table> <tr> <td></td> <td></td> <td></td> </tr> <tr> <td></td> <td></td> <td></td> </tr> <tr> <td></td> <td></td> <td></td> </tr> </table>This method has full browser support: yourNode.hasChildNodes()
The Node.hasChildNodes() method returns a Boolean value indicating whether the given Node has child nodes or not.