Home > Net >  How do I get the index of each button in a trivia game and check if the selected answer is equal to
How do I get the index of each button in a trivia game and check if the selected answer is equal to

Time:08-07

I have a trivia app that has four buttons, each with their own answer. I have implemented getElementById for each button, and have also added "click" event listeners to each one. Upon clicking the button, the function "checkAnswer" runs. This is what the function looks like so far.

function checkAnswer() {
  answer = randomQuestion.answers.find((answer) => answer.correct);
     if(answer.correct === true) {
       console.log("Correct!");
     } else {
       console.log("Incorrect");
  }
}

"randomQuestion" and "answer" are global variables. randomQuestion generates a question from a pool of questions imported from a separate file.

randomQuestion = questions[Math.floor(Math.random()*questions.length)];

I need to find the correct answer and compare it to the selected answer. I think I might need to grab the index of each button, but I am unsure how to do that.

Here is one question from my array of object questions.

export const questions = [
    {
        question: 'What year did the United State gain independence?',
        answers: [
          { text: '1776', correct: true },
          { text: '1876', correct: false },
          { text: '1676', correct: false },
          { text: '1576', correct: false }
        ]
      },

CodePudding user response:

The callback function for the addEventListener takes another parameter which we usually term as event. You can make use of the parameter to distinguish which button is clicked.

Below is the minimum reproducible example for the same.

NOTE: Please don't add same event listeners like I have added below in your production code. You can make use of the bubbling & capturing concept when in need of adding same listerner to multiple elements.

const buttons = document.querySelectorAll(".btn");

buttons.forEach((btnEl) =>
  btnEl.addEventListener("click", (event) => {
    console.log('button clicked id -', event.target.id);
  })
);
<button id="answer-1" class='btn'>Answer 1</button>
<button id="answer-2" class='btn'>Answer 2</button>
<button id="answer-3" class='btn'>Answer 3</button>
<button id="answer-4" class='btn'>Answer 4</button>

CodePudding user response:

I got carried away and wrote a class. Here's what you need to know:

  • For each answer, make an attribute of the <button>, <input type='radio'>, etc. the value of question[x].answers[y].correct x from the outer loop and y from the inner loop. (see Figure I)

    Figure I

    const btns = document.querySelectorAll('button');
    btns.forEach((btn, idx) => {
      let options = Array(4);
      options.forEach((b, i) => {
        btn.dataset.key = question[idx].answer[i].correct;
        btn.value = question[idx].answer[i].text;
      });
    });
    

    You'll have buttons that have data-key attribute -- one of them is true the other three are false. (see Figure II)

    Figure II

    `<input 
      type='button' 
      value='${question[idx].answer[i].text}'
      data-key='${question[idx].answer[i].correct}'
     >`
    
  • Next, either bind the click event to each answer individually or to a parent element. (see Figure III and Figure IV)

    Figure III

    <form>
      <input type='button' value='1776' data-key='true'>
      <input type='button' value='1876' data-key='false'>
      <input type='button' value='1676' data-key='false'>
      <input type='button' value='1576' data-key='false'>
    </form>
    

    Figure IV

    document.forms[0].onclick = handleEvent;
    // OR
    document.forms[0].elements.forEach(btn => btn.onclick = handleEvent);
    
    function handleEvents(e) {
     const origin = e.target;
     if (origin.matches('.answer')) {
       console.log(origin.dataset.key);
     }
    }
    
    

const qa=[{question:"What year did the United State gain independence?",answers:[{text:" 1776",correct:!0},{text:" 1876",correct:!1},{text:" 1676",correct:!1},{text:" 1576",correct:!1}]},{question:"In our solar system, what dwarf planet was once classified as a planet?", answers:[{text:" Moon",correct:!1},{text:" Mars",correct:!1},{text:" Pluto",correct:!0},{text:"Youranus",correct:!1}]}];

/**
 * Creates a quiz with a given array of objects and a reference to a
 * <form>
 * @param {array<object>} QA - An array of objects, the objects require 
 *        certian properties. See notes below.
 * @param {string<attr>} nameId - The value of a [name] or id attribute
 *        of a <form>
 */
class Quiz {
  constructor(QA, nameId) {
    this.root = document.forms[nameId];
    this.QA = QA;
    this.size = QA.length;
  }
  /**
   * Parses the html of the quiz and interpolates the data from the
   * given array.
   * @param {string} type - It's either "button" or "radio" if nothing
   *        is passed then @default is "radio".
   * @return this for chaining methods.
   */
  html(type = 'radio') {      
    for (let i=0; i < this.size; i  ) {
      this.root.insertAdjacentHTML('beforeend', `<li><fieldset id=QA${i} name=QA><legend id=Q${i}>${this.QA[i].question}</legend> <menu><input id=a${i} name=answer${i} type=${type} value=${this.QA[i].answers[0].text} data-key=${this.QA[i].answers[0].correct}><input id=b${i} name=answer${i} type=${type} value=${this.QA[i].answers[1].text} data-key=${this.QA[i].answers[1].correct}><input id=c${i} name=answer${i} type=${type} value=${this.QA[i].answers[2].text} data-key=${this.QA[i].answers[2].correct}><input id=d${i} name=answer${i} type=${type} value=${this.QA[i].answers[3].text} data-key=${this.QA[i].answers[3].correct}></menu></fieldset></li>`);
    }
    if (type === 'radio'.toLowerCase()) {
      for (let r=0; r < this.size; r  ) {
        let rads = this.root.elements[`answer${r}`];
        for (let s=0; s < 4; s  ) {
          rads[s].insertAdjacentHTML('beforebegin', `<label></label>`);
          rads[s].previousElementSibling.append(rads[s]);
          rads[s].insertAdjacentText('afterend', rads[s].value);
        }
      }
    }
    return this;
  }
  /**
   * Bind one or more events to <form>
   * @param {function} callback - An event handler
   * @param {event} events - A rest parameter that can accept multiples
   * @return this for chaining methods
   */
  bind(callback, ...events) {
    return [...events].forEach(event => this.root.addEventListener(event, callback));
  }
}

let x = new Quiz(qa, 'quizA');
x.html().bind(handleEvents, 'input');

let z = new Quiz(qa, 'quizB');
z.html('button').bind(handleEvents, 'click');

function handleEvents(e) {
  const origin = e.target;
  if (origin.matches('.answer')) {
    console.log(origin.dataset.key);
  }
}
html {
  font: 300 2ch/1.25 'Segoe UI'
}

form {
  list-style: decimal;
}

fieldset {
  transform: translateX(3vw);
  border: 0;
  padding: 0;
}

legend {
  transform: translate(-0.25vw, -100%);
}

menu {
  margin: 0;
  padding-top: 1.5ex;
  transform: translate(-3vw, -4vh);
}

label {
  display: list-item;
  list-style: outside lower-latin;
}

[type='radio'] {
  vertical-align: middle;
  transform: translateY(-25%)
}

[type="button"] {
  cursor: pointer;
}
<form id='quizA'></form>

<hr>

<form name='quizB'></form>

  • Related