0

I have 10 buttons in html that represents numbers from 0 to 9 that i'm using like keyboard for the number guessing game. After i find a way to get id of every button on the click with the for loop and Event listener, every other function stopped to work and i got the TypeError of -Cannot read property 'addEventListener' of undefined-. Here is the html:

let buttons = document.getElementsByClassName("number-box");
let buttonsCount = buttons.length;
for (let i = 0; i <= buttonsCount; i++) {
  buttons[i].addEventListener('click', returnId)
};

function returnId(buttons) {
  let whatHappens;
  switch (this.id) {
    case "zero":
      whatHappens = console.log('zero');
      userInput.value += 0;
      break;
    case "one":
      whatHappens = console.log('one');
      userInput.value += 1;
      break;
    case "two":
      whatHappens = console.log('two');
      userInput.value += 2;
      break;
    case "three":
      whatHappens = console.log('two');
      userInput.value += 3;
      break;
    case "four":
      whatHappens = console.log('two');
      userInput.value += 4;
      break;
    case "five":
      whatHappens = console.log('two');
      userInput.value += 5;
      break;
    case "six":
      whatHappens = console.log('two');
      userInput.value += 6;
      break;
    case "seven":
      whatHappens = console.log('two');
      userInput.value += 7;
      break;
    case "eight":
      whatHappens = console.log('two');
      userInput.value += 8;
      break;
    case "nine":
      whatHappens = console.log('two');
      userInput.value += 9;
      break;
    default:
      whatHappens = console.log('nothing');
  }
  return whatHappens;
}
<div class="container animate__animated animate__headShake">
  <button class="number-box" id="zero">0</button>
  <button class="number-box" id="one">1</button>
  <button class="number-box" id="two">2</button>
  <button class="number-box" id="three">3</button>
  <button class="number-box" id="four">4</button>
  <button class="number-box" id="five">5</button>
  <button class="number-box" id="six">6</button>
  <button class="number-box" id="seven">7</button>
  <button class="number-box" id="eight">8</button>
  <button class="number-box" id="nine">9</button>
</div>

So, this code actually works, but i'm getting an error and other functions stopped to work. What should i do?

Machavity
  • 30,841
  • 27
  • 92
  • 100
nedim
  • 3
  • 4
  • 1
    addEventListener on undefined is saying the variable you are trying to call addEventListener on is undefined. So you're elements are not being found. – Taplar Jul 28 '20 at 15:14
  • Learn to use your browser's developer tools (usually accessed with F12). If you had, you would have seen the error in the console... – Lee Taylor Aug 17 '20 at 23:42

1 Answers1

0

In your for loop, your condition uses <=, when it should just use <. This error means that you are trying to find the button in the node list with an index of the length of the list, which doesn't exist, so for that last iteration, you get the error.

let buttons = document.getElementsByClassName("number-box");
let buttonsCount = buttons.length;
for (var i = 0; i < buttonsCount; i++) {
  buttons[i].addEventListener('click', returnId)
};

function returnId(buttons) {
  let whatHappens;
  switch (this.id) {
    case "zero":
      whatHappens = console.log('zero');
      userInput.value += 0;
      break;
    case "one":
      whatHappens = console.log('one');
      userInput.value += 1;
      break;
    case "two":
      whatHappens = console.log('two');
      userInput.value += 2;
      break;
    case "three":
      whatHappens = console.log('two');
      userInput.value += 3;
      break;
    case "four":
      whatHappens = console.log('two');
      userInput.value += 4;
      break;
    case "five":
      whatHappens = console.log('two');
      userInput.value += 5;
      break;
    case "six":
      whatHappens = console.log('two');
      userInput.value += 6;
      break;
    case "seven":
      whatHappens = console.log('two');
      userInput.value += 7;
      break;
    case "eight":
      whatHappens = console.log('two');
      userInput.value += 8;
      break;
    case "nine":
      whatHappens = console.log('two');
      userInput.value += 9;
      break;
    default:
      whatHappens = console.log('nothing');
  }
  return whatHappens;
}
<div class="container animate__animated animate__headShake">
  <button class="number-box" id="zero">0</button>
  <button class="number-box" id="one">1</button>
  <button class="number-box" id="two">2</button>
  <button class="number-box" id="three">3</button>
  <button class="number-box" id="four">4</button>
  <button class="number-box" id="five">5</button>
  <button class="number-box" id="six">6</button>
  <button class="number-box" id="seven">7</button>
  <button class="number-box" id="eight">8</button>
  <button class="number-box" id="nine">9</button>
</div>

Having said that, you should not be using .getElementsByClassName() and most certainly not using it within a loop.

Additionally, you don't even need to give your buttons an id in the first place (ID's make for brittle code that doesn't scale well). You can eliminate the loop entirely by using event delegation on the parent of all the buttons and your big switch can be eliminated and a simple function with just 3 lines of code used in its place:

let userInput = document.querySelector("input");

// Just set an event listener on the parent of all the buttons
// and let any click event that originates from a button bubble
// up to the parent where it will be handled. This is called 
// event delegation and you'll set up one event handler instead
// of 10 and you won't need any loop.
document.querySelector("div.container").addEventListener("click", returnId);

let wordMappings = ["zero","one","two","three","four","five","six","seven","eight","nine"];

function returnId(event) {
  // Get the text of the clicked button (event.target)
  let text = event.target.textContent;
  
  // Update the value
  userInput.value += text;
  
  // Get the corresponding word out of the array and return it
  console.log(wordMappings[text]);
}
<div class="container animate__animated animate__headShake">
  <button class="number-box">0</button>
  <button class="number-box">1</button>
  <button class="number-box">2</button>
  <button class="number-box">3</button>
  <button class="number-box">4</button>
  <button class="number-box">5</button>
  <button class="number-box">6</button>
  <button class="number-box">7</button>
  <button class="number-box">8</button>
  <button class="number-box">9</button>
</div>

<input>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71