javascriptarraysfunctiontic-tac-toehtmlcollection

Using arr.every() on [...HTMLCollection] doesn't return true element change


I'm trying to build a Tic Tac Toe game so I tried to collect the playbox areas in an array by first using getElementsByClassName() before using spread operator to convert the collection into an array. But when I try to use the arr.every() method to check if all boxes are played, I still get false even after all the boxes are filled

This is my HTML code

<div class="board">
  <div class="board-sections">
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
   </div>
</div>

First I collected all play boxes.

let boxes = document.getElementsByClassName("play-box");
let numOfBoxes = boxes.length;

Then I converted the collection to array and applied the condition to check if all boxes are not empty

let boxesArr = [...boxes];
let checkBoxes = boxesArr.every(function(box) {
  return box.innerHTML !== "";
});

Then I created a function to check if all boxes are not empty

function checkBoard() {
  if (checkBoxes) {
    console.log("All Filled");
  }
}

Then I created a funtion to add text to each box and check if all boxes are filled by calling the checkBoard() function onclick.

for (var i = 0; i < numOfBoxes; i++) {
  boxes[i].addEventListener("click", addChip);
}

The addChip() function adds a text to each box as it's clicked, then check if all boxes are filled

function addChip() {
  this.innerHTML = "X";
  checkBoard();
}

The boxes were filled as they're clicked, and I expected the checkBoard() function to return true after all boxes are filled, but after all boxes have filled the checkBoard() function still returned false.

Here's what the full code looks like

let boxes = document.getElementsByClassName("play-box");
let numOfBoxes = boxes.length;

let boxesArr = [...boxes];
let checkBoxes = boxesArr.every(function(box) {
  return box.innerHTML !== "";
});

function checkBoard() {
  if (checkBoxes) {
    console.log("All Filled");
  }
}

for (var i = 0; i < numOfBoxes; i++) {
  boxes[i].addEventListener("click", addChip);
}

function addChip() {
  this.innerHTML = "X";
  checkBoard();
}
.board {
  text-align: center;
  max-width: 100%;
  width: 500px;
  margin: auto;
}

.board-sections {
  display: grid;
  grid-template-columns: auto auto auto;
  background: #ccc;
  gap: 5px;
  align-content: center;
}

.play-box {
  height: 100px;
  background: transparent;
  border: 1px solid #000;
  min-width: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
}
<div class="board">
  <div class="board-sections">
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
  </div>
</div>


Solution

  • It is difficult to answer your question without having the actual code. Below I assembled a possible scenario that actually works. Maybe it is helpful to you?

    const pb=[...document.querySelectorAll(".play-box")];
    document.querySelectorAll("button").forEach(b=>{
     b.addEventListener("click",ev=>{
      if(b.textContent=="check")
       console.log(pb.every(p=>p.textContent!=""))
      else
       pb.forEach(p=>p.textContent="X");
     })
    })
    .play-box {display:inline-block; width:40px;height:40px; border:1px solid grey}
    <div class="board">
      <div class="board-sections">
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div><br>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div><br>
    <div class="play-box"></div>
    <div class="play-box"></div>
    <div class="play-box"></div>
       </div>
    </div>
    <button>check</button> <button>fill</button>

    The point I was trying to make is that the .textContent of the .play-box elements must be checked after they have been filled. OP's original script did the check only once, directly after the page was loaded.

    Explanation:
    The key part in my snippet above is the expression

    pb.every(p=>p.textContent!="")
    

    It returns true if all boxes are filled in some way. In your tic-tac-toe game this will need to be executed after each setting of an "X" or an "O".

    Your checkBoard function should look like this:

    function checkBoard() {
      if (boxesArr.every(p=>p.textContent!="")) {
        console.log("All Filled");
      }
    }