Reputation: 29
I am trying to make a very simple java script quiz to try and learn the language.
var result = document.getElementById("result");
var rightAnswer = document.getElementById("correct").addEventListener("click",correctAnswer);
function correctAnswer(){
result.innerText="Correct";
};
var wrongAnswer = document.getElementsByClassName("wrong").addEventListener("click",wrongAnswer);
function wrongAnswer(){
result.innerText="Wrong";
};
When I run it and test the correct answer works fine but the wrong answers are unresponsive. When I look in the console it says that "document.getElementsByClassName(...).addEventListener is not a function" which confuses me seeing how I formatted it exactly like the other line with the exception of the "getElementsByClassName". Can I not add the same event listener to multiple buttons of the same class? HTML
<!DOCTYPE html>
<html>
<head>
<title>Quiz</title>
</head>
<body>
<p>Who was the first president of the United States?</p>
<button class='button wrong' type='button'>Thomas Jefferson</button>
<button class='button' id='correct' type='button'>George Washington</button>
<button class='button wrong' type='button'>James Madison</button>
<button class='button wrong' type='button'>John F Kennedy</button>
<p id='result'></p>
<script src='quiz.js'></script>
</body>
</html>
Upvotes: 0
Views: 76
Reputation: 34556
The error in your error console is because you can't run addEventListener()
chained to getElementsByTagName()
.
getElementsByTagName()
returns a nodeset, whereas addEventListener()
is a method of the HTML node object, not nodeset object.
In other words, it runs on a single node. This means we either need to iterate over the nodeset and bind the event to each node found, or use event delegation.
Iteration approach
var wrong = document.querySelectorAll(".wrong");
wrong.forEach(function(el) {
el.addEventListener("click",wrongAnswer, false);
});
Delegation approach
With event delegation, you bind not to each and every node but to a common parent or ancestor. You then interrogate which node triggered the event.
We can rely on this because events "bubble"; they fire not only for the element to which they're bound, but also that element's child/descendant nodes, from the innermost outwards.
In other words, the trigger element (evt.target
) and the context element (this
) may not be one and the same.
Let's imagine all your .wrong
elements live in a common container, with ID #wrong
.
We could then do:
document.querySelector('#wrong').addEventListener('click', function(evt) {
var trigger_el = evt.target;
if (!evt.target.matches('.wrong') return; //do nothing - was some other element
wrongAnswer.call(trigger_el); //call wrongAnswer in the context of the trigger element
}, false);
Upvotes: 1
Reputation:
You need to loop through the result of document.getElementsByClassName("wrong") in order to addEventListeners because getElementsByClassName will always return multiple elements. You can do so simply:
var wrongAnswer = document.getElementsByClassName("wrong");
for(n = 0; n < wrongAnswer.length; n++){
wrongAnswer[n].addEventListener("click",wrongAnswer);
}
Upvotes: 1