I have a trivia app that is almost complete. It contains an array of objects (being imported from a separate JavaScript file) containing all of my questions and four possible answers. I have a function that generates a random question from that array, stores the value into a global variable called randomQuestion
and populates the HTML buttons with four possible answers.
I previously used the onClick
event for each button within the HTML. That worked, however, there were too many questions to include in the primary JavaScript file. I moved them and exported/imported them to the app’s primary file. When I did this my checkAnswer
function no longer worked, and I got the Uncaught TypeError
warning. I was informed that in order to fix this I needed to remove the onClick
events from the HTML file and addEventListener
s to the buttons within the primary file.
Within the primary file I have captured each button with getElementById
and have added click
event listeners to each of the button variables. When the button is clicked the checkAnswer
function should check if the selected answer is equal to the correct answer, and console.log
“correct” or “incorrect”.
My problem is that I don't know how to capture the value of the answer button that is clicked and compare that to the correct answer value within the current randomQuestion
. The code below is what I’m working with.
<button id="answers-btn-1" ></button>
<button id="answers-btn-2" ></button>
<button id="answers-btn-3" ></button>
<button id="answers-btn-4" ></button>
function checkAnswer() {
answer = randomQuestion.answers;
if(answer.correct === true) {
console.log("Correct!");
} else {
console.log("Incorrect");
}
}
export const questions = [
{
question: 'What year did the United States gain independence?',
answers: [
{ text: '1776', correct: true },
{ text: '1676', correct: false },
{ text: '1576', correct: false },
{ text: `1476', correct: false }
]
},
CodePudding user response:
Instead of creating the HTML up-front this example builds the HTML from the question/answer data, adds it to the DOM, and adds one listener to a buttons container which (using event delegation) captures events from its child elements (the buttons) as they "bubble up" the DOM.
To steer away from global variables checkAnswer
accepts the array of answers and returns a new function (closure) when it is called.
answers.addEventListener('click', checkAnswer(question.answers));
That function is assigned to the listener and called when the listener is fired.
const questions=[{question:"What year did the United States gain independence?",answers:[{text:"1776",correct:true},{text:"1676",correct:false},{text:"1576",correct:false},{text:"1476",correct:false}]},{question:"What star does Earth orbit?",answers:[{text:"Moon",correct:false},{text:"Proxima Centauri",correct:false},{text:"Sun",correct:true},{text:"Roy Orbison",correct:false}]}];
// `checkAnswers` accepts the answers for the question
// and returns a new function (closure) that is assigned to the
// listener which fires when any of the child elements
// (the buttons) of the container `.answers` is clicked
// The closure keeps a reference to the answers when it is returned
function checkAnswer(answers) {
return function(e) {
// If the clicked child element is a button
// get its textContent, `find` the correct answer
// from the answers array, destructure its text value
// and then compare it to the textContent of the clicked button
if (e.target.matches('.answer')) {
const { textContent } = e.target;
const { text } = answers.find(answer => answer.correct);
if (textContent === text) {
console.log('Correct');
} else {
console.log('Incorrect');
}
}
}
}
// Accepts the question answers and builds
// the buttons HTML
function buildAnswers(answers) {
return answers.map(answer => {
return `<button >${answer.text}</button>`;
}).join('');
}
// Builds the question which is added to the
// element with the `question` class. It adds the
// question to an <h3> elementm, and calls `buildAnswers`
// with the answers as an argument to return the answers HTML
// Note: `map` returns an array so we need to join into into
// a string
function buildQuestion(question) {
return `
<h3>${question.question}</h3>
<section >
${buildAnswers(question.answers)}
</section>
`;
}
// Get a random number based on the length of
// the questions array
function rnd(questions) {
return Math.floor(Math.random() * questions.length);
}
// The main function
// 1) Gets a random question from the array
// 2) Gets the question element
// 3) Creates the question HTML
// 4) Inserts the HTML into the question element
// 5) It grabs the answers container element
// 6) Adds an event listener to it which calls `checkAnswer`
// with the set of available answers as an argument, which
// returns a function that is used when a button is clicked
function main() {
const question = questions[rnd(questions)];
const el = document.querySelector('.question');
const html = buildQuestion(question);
el.insertAdjacentHTML('beforeend', html);
const answers = document.querySelector('.answers');
answers.addEventListener('click', checkAnswer(question.answers));
}
// Call main
main();
.answer { margin-right: 0.3em; border-radius: 5px; }
.answer:hover { cursor: pointer; background-color: lightblue;}
<section ></section>
Additional documentation
CodePudding user response:
You can use form with submit buttons
const questions = [
{
question: 'What year did the United States gain independence?',
answers: [
{ text: '1776', correct: true },
{ text: '1676', correct: false },
{ text: '1576', correct: false },
{ text: '1476', correct: false }
]
}];
const currentQ = questions[0];
document.getElementById('question').textContent = currentQ.question;
const form = document.getElementById('form');
for (let i = 0; i < currentQ.answers.length; i ) {
const btn = document.createElement('button');
btn.type = 'submit';
btn.textContent = currentQ.answers[i].text;
btn.value = currentQ.answers[i].text;
form.appendChild(btn);
}
function handleSubmit(e) {
e.preventDefault();
const answer = e.submitter.value;
const correctAnswer = currentQ.answers.find(ans => ans.correct);
console.log(answer === correctAnswer.text ? 'Correct' : 'Incorrect');
}
<form id="form" onsubmit="handleSubmit(event)">
<p id="question">question?</p>
</form>