1

So I'm applying my recent knowledge of Javascript and the DOM. However, I'm getting an error message saying "addEventListener is not defined" when I attempt to use querySelectorAll or getElementsByClassName for the same button, but for different questions. Here's my code block.

var input = document.getElementsByClassName('userInput');
var submitButton = document.getElementsByClassName('.submit');
var numAnsCorrect = 0;
var numAnsIncorrect = 0;
var questionsRight = document.querySelector('.questionsRight');
var questionsWrong = document.querySelector('.questionsWrong');


submitButton.addEventListener('click', () => {
    let submitButton = document.querySelector('.submit');
    let userInput = document.querySelector('.userInput');
    let response = userInput.value;
    response = response.toUpperCase();
    var answer = ['SAVANNAH', 'NATHAN DEAL'];
    let result = document.querySelector('.question-result');
    for (var i = 0; i < answer.length; i++) {
        if (response === answer[i]) {
            result.textContent += ' That is correct!';
            numAnsCorrect++;
            questionsRight.textContent = numAnsCorrect;
            submitButton.style.display = "none";
        } else {
            result.textContent += ' That is incorrect';
            numAnsIncorrect++;
            questionsWrong.textContent = numAnsIncorrect;
            submitButton.style.display = "none";
        }
    }
});

What am I doing wrong? I assumed I would have to loop through the buttons or maybe have another equality operator for button but I'm not too sure.

Shane Harper
  • 63
  • 1
  • 9

3 Answers3

1

When you use querySelectorAll() or getElementsByClassName(), you get a list of Elements back. You need to pull an element out of that list to be able to call addEventListener() on it.

example:

var userInputs = document.getElementsByClassName('userInput');
var input = userInputs[0];
MicronXD
  • 2,190
  • 16
  • 24
1

Can't be 100% certain with what's wrong with the OP code since HTML isn't provided, but I can safely assume that there a number elements you want to be listening for events. There are a couple of ways to meet your objective:

  1. Use a loop or an array method to iterate through multiple elements. On each loop assign an event handler on the current element.

    for (let i=0; i < list.length; i++) {
      list[i].addEventListener('click', eventHandler);
    } 
    
  2. Assign an on event attribute to each element.

    <button onclick='eventHandler()'>CLICK</button>
    <button onclick='eventHandler()'>CLICK</button>
    
  3. Event Delegation is a pattern that takes advantage of Event Bubbling, and the Event Object. Basically if there's a group of elements that we need to listen for events, we simply assign one eventListener to an ancestor element that the group of elements have in common (we can even use document or window.) In doing so, our resources are not tied up in several eventHandlers / eventListeners and we don't get Carpal Tunnel Syndrome typing in 100 onclick events.⭐ Recommended


Demo 1

Registering eventHamdlers/eventListeners on on each iteration of a NodeList or an array


/* Collect all .btn class in a NodeList then convert it into
|| an array
*/
var btnArray = Array.from(document.querySelectorAll('.btn'));

// Reference the output.out
var out = document.querySelector('.out');

/* run arry through forEach() array method...
|| on each loop assign an onclick eventHandler or eventListener to
|| current button.btn
*/
btnArray.forEach(function(btn, idx) {

  btn.addEventListener('click', function() {

    var txt = btn.textContent;

    out.textContent = txt;
    
  });

});
.out,
button {
  display: inline-block;
  color: blue;
  font: 900 20px/1 Consolas;
  width: 5ch;
  text-align: center;
}

.out {
  color: red;
  width: 100%;
  font-size: 30px
}
<fieldset class='set'>
  <button class='btn'>BTN0</button>
  <button class='btn'>BTN1</button>
  <button class='btn'>BTN2</button>
  <button class='btn'>BTN3</button>
  <button class='btn'>BTN4</button>
  <button class='btn'>BTN5</button>
  <button class='btn'>BTN6</button>
  <button class='btn'>BTN7</button>
  <button class='btn'>BTN8</button>
  <button class='btn'>BTN9</button>
  <button class='btn'>BTNA</button>
  <button class='btn'>BTNB</button>
  <button class='btn'>BTNC</button>
  <button class='btn'>BTND</button>
  <button class='btn'>BTNE</button>
  <button class='btn'>BTNF</button>
  <output class='out'>X</output>
</fieldset>

Demo 2

Assign an on event attribute on each element


var out = document.querySelector('.out');

function eventHandler(event) {
  var txt = event.target.textContent;
  out.value = txt;
}
.out,
button {
  display: inline-block;
  color: blue;
  font: 900 20px/1 Consolas;
  width: 5ch;
  text-align: center;
}

.out {
  color: red;
  width: 100%;
  font-size: 30px
}
<fieldset class='set'>
  <button class='btn' onclick="eventHandler(event,this)">BTN0</button>
  <button class='btn' onclick="eventHandler(event,this)">BTN1</button>
  <button class='btn' onclick="eventHandler(event,this)">BTN2</button>
  <button class='btn' onclick="eventHandler(event,this)">BTN3</button>
  <button class='btn' onclick="eventHandler(event,his)">BTN4</button>
  <button class='btn' onclick="eventHandler(event,this)">BTN5</button>
  <button class='btn' onclick="eventHandler(event,this)">BTN6</button>
  <button class='btn' onclick="eventHandler(event,this)">BTN7</button>
  <button class='btn' onclick="eventHandler(event,this)">BTN8</button>
  <button class='btn' onclick="eventHandler(event,this)">BTN9</button>
  <button class='btn' onclick="eventHandler(event,this)">BTNA</button>
  <button class='btn' onclick="eventHandler(event,this)">BTNB</button>
  <button class='btn' onclick="eventHandler(event,this)">BTNC</button>
  <button class='btn' onclick="eventHandler(event,this)">BTND</button>
  <button class='btn' onclick="eventHandler(event,this)">BTNE</button>
  <button class='btn' onclick="eventHandler(event,this)">BTNF</button>
  <output class='out'>X</output>
</fieldset>


Demo 3

Event Delegation

Details commented in Demo

Recommended


// Reference the parent element
var set = document.querySelector('.set');

/* Register parent to click event it will trigger not only when 
|| it is clicked, it will also trigger callback if any of ts 
|| descebdant elements are clicked as well.
*/
set.addEventListener('click', eventHandler);

// Callback function passes the Event Object
function eventHandler(even) {

  // Reference an output.out
  var out = document.querySelector('.out');

  // if the clicked element (event.target) has the class .btn...
  if (event.target.className === "btn") {

    // ...Get event.target's text
    var txt = event.target.textContent;

    // Display the text
    out.value = txt;
  }

  return false;

};
.out,
button {
  display: inline-block;
  color: blue;
  font: 900 20px/1 Consolas;
  width: 5ch;
  text-align: center;
}

.out {
  color: red;
  width: 100%;
  font-size: 30px
}
<fieldset class='set'>
  <button class='btn'>BTN0</button>
  <button class='btn'>BTN1</button>
  <button class='btn'>BTN2</button>
  <button class='btn'>BTN3</button>
  <button class='btn'>BTN4</button>
  <button class='btn'>BTN5</button>
  <button class='btn'>BTN6</button>
  <button class='btn'>BTN7</button>
  <button class='btn'>BTN8</button>
  <button class='btn'>BTN9</button>
  <button class='btn'>BTNA</button>
  <button class='btn'>BTNB</button>
  <button class='btn'>BTNC</button>
  <button class='btn'>BTND</button>
  <button class='btn'>BTNE</button>
  <button class='btn'>BTNF</button>
  <output class='out'>X</output>
</fieldset>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • That's what I was trying to do - loop through the input fields and then compare each answer to an index in an array called 'answers'. Let me try to paste my HTML in the comment below. – Shane Harper May 29 '18 at 11:16
  • So it's not letting me paste code here, but what I had was an ol with each li having an input field and submit button. In that case would I have to set up 2 different loops to get the answer or try to incorporate them into one? – Shane Harper May 29 '18 at 11:24
  • You should really consider using Demo 3. in Demo 3 all you need to do is determine `e.target`, setup and use **ONE EVENTLISTENER()** for any number of elements, no loops, you don't even need to know any IDs or classes. – zer00ne May 29 '18 at 14:17
-1

I have this issue before. Try console.log on submitButton . But the best to fetch DOM element is by getElementsById in some cases. Or use JQuery for advanced purpose.

Amin Shazrin
  • 83
  • 1
  • 8