There's no sound of success when you click on the tic-tac-toe board

I'm encountering an issue with my code where the tiles are not clickable and nothing is being displayed. I suspect that the problem lies in this section: tiles.forEach( (tile, index) => { tile.addEventListener('click', () => userAction(tile, index)); });. Could it be a connectivity problem with the scripts? Can someone pinpoint the error?

window.addEventListener('DOMContentLoaded', () => {
     const tiles = Array.from(document.querySelectorAll('.tile'));
     const playerDisplay = document.querySelector('.display-player');
     const resetButton = document.querySelector('#reset');
     const announcer = document.querySelector('.announcer');

     let board = ['', '', '', '', '', '', '', '', '',];
     let currentPlayer = X;
     let isGameActive = true;

     const X_WON = 'X_WON';
     const O_WON = 'O_WON';
     const TIE = 'TIE';

     /*
     Board index
     [0][1][2]
     [3][4][5]
     [6][7][8]
     
     */

     const winningConditions = [
        [0, 1, 2]
        [3, 4, 5]
        [6, 7, 8]
        [0, 3, 6]
        [1, 4, 7]
        [2, 5, 8]
        [0, 4, 8]
        [2, 4, 6]
     ]

     function handleResultValidation() {
        let roundWon = false;
        for (let i = 0; i <= 7; i++) {
            const winCondition = winningConditions[i];
            const a = board[winCondition[0]];
            const b = board[winCondition[1]];
            const c = board[winCondition[2]];
            if (a === '' || b === '' || c === '') {
                continue;
            }
            if (a === b && b === c) {
                roundWon = true;
                break;
            }
        }

        if (roundWon) {
            announce(currentPlayer === 'X' ? X_WON : O_WON);
            isGameActive = false;
            return;
        }

        if (!board.includes(''))
        announce(TIE);
     }

     const announce = (type) => {
        switch(type){
            case O_WON:
                announcer.innerHTML = `Player <span class="O">O</span> Won`;
                break;
            case X_WON:
                announcer.innerHTML = `Player <span class="X">X</span> Won`;
                break;
            case TIE:
                announcer.innerText = 'Tie'
        }
        announcer.classList.remove('hide');
     };

     const isValidAction = (tile) => {
        if (tile.innerText === 'X' || tile.innerText === 'O'){
            return false;
        }

        return true;
     }

     const updateBoard = (index => {
        board[index] = currentPlayer;
     })

     const changePlayer = () => {
        playerDisplay.classList.remove(`player${currentPlayer}`);
        currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
        playerDisplay.innerText = currentPlayer;
        playerDisplay.classList.add(`player${currentPlayer}`);
     }

     const userAction = (tile, index) => {
        if(isValidAction(tile) && isGameActive) {
            tile.innerText = currentPlayer;
            tile.classlist.add(`player${currentPlayer}`);
            updateBoard(index);
            handleResultValidation();
            changePlayer();
        }
     }

     const resetBoard = () => {
        board = ['', '', '', '', '', '', '', '', '',];
        isGameActive = true;
        announcer.classList.add('hide');

        if (currentPlayer === 'O') {
            changePlayer();
        }

        tiles.forEach(tile => {
            tile.innerText = '';
            tile.classList.remove('X')
            tile.classList.remove('O')
        });
     }

     tiles.forEach( (tile, index) => {
        tile.addEventListener('click', () => userAction(tile, index));
     });

    resetButton.addEventListener('click', resetBoard);
});
* {
    padding: 0;
    margin: 0;
    font-family: Verdana, Geneva, Tahoma, sans-serif;
}

.background {
    background-color: pink;
    height: 100vh;
    padding-top: 1px;
}

.title {
    color: orange;
    text-align: center;
    font-size: 40px;
    margin-top: 1%;
}

.display {
    color: orange;
    font-size: 25px;
    text-align: center;
    margin-top: 1em;
    margin-bottom: 1em;
}

.hide {
    display: none;
}

.container {
    margin: 0 auto;
    display: grid;
    grid-template-columns: 33% 33% 33%;
    grid-template-rows: 33% 33% 33%;
    max-width: 900px;
}

.tile {
    border: 5px solid orange;
    min-width: 100px;
    min-height: 250px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 50px;
    cursor: pointer;
}

.X {
    color: aquamarine;
}

.O {
    color: brown;
}

.controls {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;

}

#reset {
    background-color: orange;
    color: white;
    padding: 8px;
    border-radius: 8px;
    border: none;
    font-size: 20px;
    margin-left: 1em;
    cursor: pointer;
}
<!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="index.css">
    <script src="index.js"></script>
<title>Tic-Tac-Toe</title>
</head>
<body>
    <!-- <script src="index.js"></script> -->
    <main class="background">

        <section class="title">
            <h1>Tic Tac Toe</h1>
        </section>

        <section class="display">
            Player <span class="display-player X">X</span>'s turn
        </section>

        <section class="container">
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
            <div class="tile"></div>
        </section>

        <section class="display announcer hide"></section>
        <section class="controls">
            <button id="reset">Reset Game</button>
        </section>
    </main>
</body>
</html>

Answer №1

  1. Ensure the currentPlayer variable is assigned a string value 'X', not just the variable name X

let currentPlayer = 'X';

  1. Don't forget to include commas , between elements in your array
const winningConditions = [
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8],
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8],
        [0, 4, 8],
        [2, 4, 6]
     ]
  1. The correct property for handling classes is classList, not classlist

tile.classList.add(`player${currentPlayer}`);

Answer №2

Upon running the code provided, I encountered an error at line 8 of index.js. It may be helpful to start troubleshooting from there.

https://i.sstatic.net/APQxL.png

  1. To address the first issue, modify line 25 in index.js as follows: change let currentPlayer = X; to
    let currentPlayer = "X";

https://i.sstatic.net/1gXKZ.png

The second error can be resolved by ensuring comma delimiters are added to the array on each line:

const winningConditions = [
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8],
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8],
        [0, 4, 8],
        [2, 4, 6]
     ]

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Animating Array of Paragraphs with JQuery: Step-by-Step Guide to Displaying Paragraph Tags Sequentially on Each Click

var phrases = ['phraseone', 'yet another phrase', 'once more with feeling']; $(".btn").on('click', function() { for(var i=0; i < phrases.length; i++) { container.innerHTML += '<p>' + ...

Retrieve data using the designated key and convert it into JSON format

If I have the following JSON array: [ {"data": [ {"W":1,"A1":"123"}, {"W":1,"A1":"456"}, {"W":2,"A1":"4578"}, {"W":2,"A1":"2423"}, {"W":2,"A1":"2432"}, {"W":2,"A1":"24324" ...

Alter the appearance of a functional component upon clicking

The AnswerScreen component is currently loading a set of MyButton components. I am trying to adjust the style of the MyButton that was clicked, specifically changing the backgroundColor. Unfortunately, my code is not functioning as expected. I have notic ...

When attempting to utilize putImageData on the HTML5 canvas context, an error occurs stating that the overload resolution has failed

While following the MDN canvas tutorial, I encountered an issue with a code snippet I wrote. The code is supposed to color the top left corner (50x50 pixels) of the canvas in red. However, I'm receiving an error message that says Overload resolution ...

Incorporate row numbering feature into jQuery DataTables

Is there a way to have jQuery datatables generate a row number column in the first column, similar to a datagrid in VB? This is what I'm aiming for: If you have any insights on how this can be achieved, please share! ...

What is the best way to vertically center these two boxes within the confines of this red box?

Is there a way to vertically align the white and green boxes inside the red box? I'm aiming for a layout similar to the one shown in the image below. Your help is greatly appreciated! Check out this demo on jsfiddle. <style> *{ padd ...

I have a question for you: How can I customize the font size in Material-UI TextField for different screen sizes?

I'm facing a challenge in Material-UI where I need to set different font sizes for TextField. While it may be simple in HTML/CSS, it's proving to be tricky in Material-UI. Can anyone help me figure out how to achieve this? The code snippet below ...

Using ES6 Promises with jQuery Ajax

Trying to send a post request using jQuery with an ES6 promise: Function used: getPostPromise(something, anotherthing) { return new Promise(function(resolve, reject) { $.ajax({ url: someURL, type: 'post', contentType: &a ...

Simple method to modify the text size of the entire HTML page

Looking for a way to adjust the font size of an entire HTML document? I'd like to have two buttons - one to increase the font size and the other to decrease it. Each button will trigger a JavaScript function; function increaseFontSize(){ //Increase ...

What distinguishes between employing a div versus a canvas element for a three.js display?

While it is commonly believed that three.js requires the HTML5 <canvas> element, I have found success in using a simple <div> by assigning height and width properties and then adding the WebGLRenderer.domElement as its child within the HTML str ...

Node receiving empty array as result after processing post request

My current task involves testing the post method on Postman. Strangely, every time I post the result it shows an empty array []. Upon further investigation by console logging on the node side, it also returns an empty array. CREATE TABLE users ( user_ ...

I am struggling to render the pages and components in React while using BrowserRouter

Below is the code snippet for App.js and Home.js that I'm working on. My aim is to showcase the Home.js component in the browser. App.js import "./App.css"; import { Route, BrowserRouter } from "react-router-dom"; import Home from ...

Form Validation Issues Detected

Could someone help explain why the code below is causing an error according to W3C guidelines: <form id="" method="post" action="" /> <input type="text" name="" title="" tabindex="10" class="" /> <inp ...

Dealing with Sideways Overflow Using slideDown() and slideUp()

Attempting to use slideUp() and slideDown() for an animated reveal of page elements, I encountered difficulty when dealing with a relatively positioned icon placed outside the element. During these animations, overflow is set to hidden, resulting in my ico ...

The progress bar for Ng-file-upload does not function properly when used in conjunction with offline

Using ng-file-upload for file uploading in my home has been successful, as I am able to upload files without any issues. However, I encountered a problem where the progress bar only appears when offlinejs is disabled in the index.html file. It seems that ...

"Efficiently rendering a variety of textures using a single draw

Hey there, I am interested in creating multiple cubes with unique textures for each cube. In order to optimize performance, I've combined the geometries into a single mesh. However, I've encountered an issue with textures as I currently require a ...

Change the JavaScript code to output HTML rather than just plain text

I've created a small plugin for tinymce4 that adds an additional dropdown menu with a list of headers (e.g. h1, h2...). The issue I'm facing is that I'm trying to display these header elements with their corresponding styles (e.g. <h1> ...

retrieveValue() for SelectionDropdown

I have a simple task - I just need to retrieve the name of the Company and store it in the database. Initially, I was able to achieve this using plain text and the code snippet below: sport: this.refs.company.getValue(), which worked perfectly. However, ...

What could be the reason for the discrepancy between document.activeElement and the focused element in JSDom while testing a Vue component using Jest?

Currently, I am in the process of testing a Vue.js 2 component using a combination of vue-test-utils and jest. One functionality of this component is that it automatically sets focus to a specific element. When examining JSDom, we expect it to reference ...

Replicating a Bootstrap element without transferring all event listeners

Recently, I posted a query on Stack Overflow regarding the cloning of a bootstrap element while excluding the copied event listener. The solution provided was to refrain from passing true to the clone() function. Upon further reflection, I've realize ...