Javascript - How to Know If an Element Is Empty?

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>
1

6 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 id="container"></div>

Careful as line breaks count as text though.

1

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>&nbsp;<span> will result in 1 and <span>&nbsp;<span>&nbsp;</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 id="SomeElement" />

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 id="TicTacToe">
  <div>⚬</div>
  <div>×</div>
  <div>×</div>
  <div>⚬</div>
  <div>⚬</div>
  <div>×</div>
  <div></div>
  <div>×</div>
  <div>⚬</div>
</div>
0

You 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>

HasClass Reference:

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") {

}
1

please 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 id="title">
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.

Documentation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Robert Thorne

Robert Thorne

Automotive & Future Transportation Editor

Robert Thorne covers electric vehicle innovations, autonomous driving systems, global mobility trends, and automotive engineering developments.

Share this article
Twitter Facebook Pinterest