Search code examples
javascriptfunctionaddeventlistener

JavaScript Hangman game, problem with event listener


When a button is clicked and it equals any letter of the answer word, the button should turn green (and show the letter), otherwise red.

The problem seems to be something with the event listener buttonGrid.addEventListener(...);

The function checkLetter() works only for the first question/answer, after the first question/answer when a button is clicked both "if" and "else" block run at the same time, and it marks the button as incorrect even if it is the right button, creates unnecessary incorrect guesses and stops the program.

CODE PEN : https://codepen.io/randomname031/pen/gOZvepQ

Here is the function:

function checkLetter(spanarray, spanletter) {
    let l = spanarray.length;

    buttonGrid.addEventListener("click", (event) => {
        attempts += 1;

        if (!event.target.classList.contains("not-this")) {
            if (spanletter.includes(event.target.textContent)) {
                // CORRECT
                event.target.classList.add("correct");
                event.target.disabled = true;

                spanarray.forEach((value) => {
                    if (value.textContent === event.target.textContent) {
                        value.classList.remove("hide");
                        score += 10;
                        l--;
                        console.log(l);
                    }
                });

                if (l === 0) {
                    setTimeout(() => {
                        clearGrid();
                        printQuestion();
                    }, 500);
                }
            } else {
                // INCORRECT
                event.target.classList.add("incorrect");
                event.target.disabled = true;
                guesses--;
                incorrectGuess.textContent = guesses;
                score -= 10;

                if (guesses === 0) {
                    endgame();
                }
            }
        }
    });
}

I tried every possible way but I couldn't fix it.

  1. Adding and removing the event listener
  2. Putting the event listener to another function
  3. stopPropagation() ~don't know if I used it the right way
  4. and also asked ChatGPT, and it made it even worse.

Solution

  • Make the function arguments as global scope variables, and pass only the function definition to the addEventListener, otherwise it will create a new event listener for each question since the arguments will differ for each call. Also, with this approach it is sufficient to add the event listener only once:

    /* DISPLAY QUESTIONS AND ANSWERS */
    let spanArray = [];
    let spanLetter = [];
    let l = 0;
    
    
    function printQuestion() {
        answer.innerHTML = "";
    
        let randomIndex = Math.floor(Math.random() * newArr.length);
        spanArray = [];
        spanLetter = [];
    
        if (newArr.length > 0) {
            question.textContent = newArr[randomIndex].q;
            newArr[randomIndex].a
                .toUpperCase()
                .split("")
                .forEach((value) => {
                    let p = document.createElement("p");
    
                    let span = document.createElement("span");
                    span.textContent = value;
                    spanArray.push(span);
                    spanLetter.push(value);
    
                    p.appendChild(span);
                    answer.appendChild(p);
                });
    
            l = spanArray.length
         
    
            newArr.splice(randomIndex, 1);
    
            if (newArr.length === 0) {
                endgame();
            }
        } else {
            endgame();
        }
    }
    
    function checkSpan(event) {
    
        const target = event.target
    
        attempts += 1;
    
        if (!target.classList.contains("not-this")) {
            if (spanLetter.includes(target.textContent)) {
                // CORRECT
                target.classList.add("correct");
                target.disabled = true;
    
                spanArray.forEach((value) => {
                    if (value.textContent === target.textContent) {
                        value.classList.remove("hide");
                        score += 10;
                        l--;
                    }
                });
    
                if (l === 0) {
                    setTimeout(() => {
                        clearGrid();
                        printQuestion();
                    }, 500);
                }
            } else {
                // INCORRECT
                target.classList.add("incorrect");
                target.disabled = true;
                guesses--;
                incorrectGuess.textContent = guesses;
                score -= 10;
    
                if (guesses === 0) {
                    endgame();
                }
            }
        }
    }
    
    buttonGrid.addEventListener("click", checkSpan);