skip to Main Content

I have to make a trivia webpage where you have a question with answers displayed on screen, with 10 questions to cycle through.

I have an array from a json file which contained the info.
I bring in the info, grab the first question, and the related options and if the answer is correct (all stored in the array)

in a for each loop, create an eventlistener, when a button is pressed, checks if the option is correct or not, add score then does a finishcheck.

which increases index, check if the new index is iwthin the length of the questions – prints next question, and send back to the loop.

else it shows the finals score.

the issue is that my index is doubling. in the html console the questions related to each index is printed. so it’s cycling through each index, printing the answers but only allowing answers to questions 1,2,4,8 are ever shown on screen.

changed this.index to all the methods off incrementing, ++, += 1, i = i + 1.

if i take out the loop() from the finishcheck, it increments 1 by 1 normally,
tried adding a second event listener to o, to initiate the finishcheck function to no avail.

  finishCheck() {
    this.index += 1;
    if (this.index < this.questions.length) {
      this.showQuestion();
      this.loop();
    } else {
      this.showScore();
      this.hideAnswers();
    }
  }

  loop() {
    const h = document.querySelectorAll(".btn-primary");
    h.forEach((o, i) => {
      o.innerHTML = this.questions[this.index].options[i].option;
      console.log(this.questions[this.index].options[i].option);
      o.addEventListener("click", () => {
        if (this.questions[this.index].options[i].isCorrect) {
          this.score++;
        }this.finishCheck();
      });
    }
    );
  }

2

Answers


  1. You can use below iteration mechanism to iterate over questions and apply click handler to individual button that won’t call same handler again and increment the index..

    <script>
        // Questions will be asked
        const Questions = [{
            id: 0,
            q: "What is capital of India?",
            a: [{ text: "gandhinagar", isCorrect: false },
                { text: "Surat", isCorrect: false },
                { text: "Delhi", isCorrect: true },
                { text: "mumbai", isCorrect: false }
            ]
        
        },
        {
            id: 1,
            q: "What is the capital of Thailand?",
            a: [{ text: "Lampang", isCorrect: false, isSelected: false },
                { text: "phuket", isCorrect: false },
                { text: "Ayutthaya", isCorrect: false },
                { text: "Bangkok", isCorrect: true }
            ]
        
        },
        {
            id: 2,
            q: "What is the capital of Gujarat",
            a: [{ text: "surat", isCorrect: false },
                { text: "vadodara", isCorrect: false },
                { text: "gandhinagar", isCorrect: true },
                { text: "rajkot", isCorrect: false }
            ]
        
        }
        
        ]
        
        // Set start
        var start = true;
        
        // Iterate
        function iterate(id) {
        
        // Getting the result display section
        var result = document.getElementsByClassName("result");
        result[0].innerText = "";
        
        // Getting the question
        const question = document.getElementById("question");
        
        
        // Setting the question text
        question.innerText = Questions[id].q;
        
        // Getting the options
        const op1 = document.getElementById('op1');
        const op2 = document.getElementById('op2');
        const op3 = document.getElementById('op3');
        const op4 = document.getElementById('op4');
        
        
        // Providing option text 
        op1.innerText = Questions[id].a[0].text;
        op2.innerText = Questions[id].a[1].text;
        op3.innerText = Questions[id].a[2].text;
        op4.innerText = Questions[id].a[3].text;
        
        // Providing the true or false value to the options
        op1.value = Questions[id].a[0].isCorrect;
        op2.value = Questions[id].a[1].isCorrect;
        op3.value = Questions[id].a[2].isCorrect;
        op4.value = Questions[id].a[3].isCorrect;
        
        var selected = "";
        
        // Show selection for op1
        op1.addEventListener("click", () => {
            op1.style.backgroundColor = "lightgoldenrodyellow";
            op2.style.backgroundColor = "lightskyblue";
            op3.style.backgroundColor = "lightskyblue";
            op4.style.backgroundColor = "lightskyblue";
            selected = op1.value;
        })
        
        // Show selection for op2
        op2.addEventListener("click", () => {
            op1.style.backgroundColor = "lightskyblue";
            op2.style.backgroundColor = "lightgoldenrodyellow";
            op3.style.backgroundColor = "lightskyblue";
            op4.style.backgroundColor = "lightskyblue";
            selected = op2.value;
        })
        
        // Show selection for op3
        op3.addEventListener("click", () => {
            op1.style.backgroundColor = "lightskyblue";
            op2.style.backgroundColor = "lightskyblue";
            op3.style.backgroundColor = "lightgoldenrodyellow";
            op4.style.backgroundColor = "lightskyblue";
            selected = op3.value;
        })
        
        // Show selection for op4
        op4.addEventListener("click", () => {
            op1.style.backgroundColor = "lightskyblue";
            op2.style.backgroundColor = "lightskyblue";
            op3.style.backgroundColor = "lightskyblue";
            op4.style.backgroundColor = "lightgoldenrodyellow";
            selected = op4.value;
        })
        
        // Grabbing the evaluate button
        const evaluate = document.getElementsByClassName("evaluate");
        
        // Evaluate method
        evaluate[0].addEventListener("click", () => {
            if (selected == "true") {
                result[0].innerHTML = "True";
                result[0].style.color = "green";
            } else {
                result[0].innerHTML = "False";
                result[0].style.color = "red";
            }
        })
        }
        
        if (start) {
        iterate("0");
        }
        
        // Next button and method
        const next = document.getElementsByClassName('next')[0];
        var id = 0;
        
        next.addEventListener("click", () => {
        start = false;
        if (id < 2) {
            id++;
            iterate(id);
            console.log(id);
        }
        
        })
        
    </script>
    
    Login or Signup to reply.
  2. This is a WAY overblown answer but I decided to have some fun.

    Here I created a class and created questions an answers which show when I make a choice change.

    Notice how I loop through the questions and add new select options based on questions and then the options for each.

    As a bonus I show how to add a new question once my class instance is created.

    Notice how I add event listeners to the dynamically create elements and also trigger custom events when a change is made to do validation (not fancy) of the choice, then set a dataset value which is used in the CSS just for fun.

    const MyQuestions = class {
      questions = [{
        questionText: "What do we know",
        answer: "rock",
        options: [{
          text: "hairy cat",
          value: "cat"
        }, {
          text: "big rock",
          value: "rock"
        }, {
          text: "Brick House",
          value: "house"
        }]
      }, {
        questionText: "What do we Love",
        answer: "cat",
        options: [{
          text: "hairy cat",
          value: "cat"
        }, {
          text: "big rock"
        }, {
          text: "Brick House"
        }]
      }, {
        questionText: "What do we Eat",
        answer: "Cheesy Toast",
        options: [{
          text: "hairy cat"
        }, {
          text: "big rock"
        }, {
          text: "Cheesy Toast"
        }]
      }];
      index = 0;
      customEvents = {
        toggleElement: new CustomEvent("show", {
          detail: {
            this: this,
          },
        }),
        wrong: new Event("wrong"),
        showScore: new Event("showScore"),
        hideAnswers: new Event("hideAnswer"),
        finishCheck: new Event("finishCheck")
      };
    
      selector = ".btn-primary";
    
      constructor(questions, selector) {
        this.questions = questions ? questions : this.questions;
        // this.selector = selector;
        this.questions.forEach((q, idx) => {
          // this.addElement(q, idx);
          this.addElementFromTemplate(q, idx);
        });
      }
    
      addOptions(options, sel) {
        options.forEach((optn, i) => {
          const newOpt = document.createElement('option');
          newOpt.value = typeof optn.value != "undefined" ? optn.value : optn.text;
          newOpt.textContent = optn.text;
          sel.appendChild(newOpt);
        });
      }
    
      addElementFromTemplate(question, idx) {
        const template = document.querySelector('#questionBlock');
        const clone = template.content.cloneNode(true);
        const cloneQuest = clone.querySelector(".question");
        const choices = cloneQuest.querySelector(".choices");
        choices.dataset.answer = question.answer ? question.answer : "wrong";
        const qLab = choices.querySelector("label");
        const qtext = qLab.querySelector(".question-text");
        qtext.textContent = `${question.questionText}`;
        const qsel = cloneQuest.querySelector("select");
        const id = `question${idx}`;
        qLab.setAttribute("for", id);
        qsel.setAttribute("id", id);
        this.addOptions(question.options, qsel);
        const btn = cloneQuest.querySelector("button");
        btn.textContent = `See Question ${idx}`;
        const currentDiv = document.querySelector(".fun-buttons-container");
        currentDiv.appendChild(cloneQuest);
        // see how this is "live"
        choices.addEventListener('wrong', this.questionWrong);
        choices.addEventListener('show', this.showQuestion);
        btn.addEventListener('click', this.clickHandler);
        qsel.addEventListener('change', this.checkAnswerHandler);
      }
    
      questionWrong = event => {
        event.target.dataset.showhide = "wrong";
        const newt = document.querySelector('#errorBlock')
          .content.cloneNode(true).querySelector('.woops');
        event.target.appendChild(newt);
      }
      checkAnswerHandler = event => {
        const val = event.target.value;
        const parent = event.target.closest('.choices');
        const tpl = document.querySelector('#errorBlock');
        const er = tpl.content.cloneNode(true).querySelector('.woops');
        if (parent.dataset.answer == val) {
          parent.dataset.showhide = "good";
          er.textContent = "Yay! " + val;
        } else {
          parent.dataset.showhide = "wrong";
          er.textContent = "Wrong! " + val;
        }
        parent.append(er);
      }
      showQuestion = event => {
        let showHide = event.target.dataset.showhide;
        event.target.dataset.showhide = showHide == "show" ? "blue" : showHide == "blue" ? "hide" : "show";
      }
      showScore(event) {}
      hideAnswers(event) {}
      clickHandler = (event) => {
        const parent = event.target.closest('.question');
        parent.querySelector('.choices').dispatchEvent(this.customEvents.toggleElement);
      }
    
      finishCheck(el, index) {
        this.index += 1;
        if (this.index < this.questions.length) {
          this.showQuestion();
          this.loop();
        } else {
          this.showScore();
          this.hideAnswers();
        }
      }
    
      loop() {
        const h = document.querySelectorAll(this.selector);
        console.log(this.selector, h.length);
        h.forEach(finishCheck, this);
        h.forEach((o, i) => {
          o.innerHTML = this.questions[this.index].options[i].option;
          console.log(i, this.questions[this.index].options[i].option);
        });
      }
    };
    
    const quest = new MyQuestions();
    let newQ = {
      questionText: "How hard is this?",
      answer: "easy",
      options: [{
        text: "Hard"
      }, {
        text: "easy"
      }, {
        text: "I don't know"
      }]
    };
    quest.addElementFromTemplate(newQ, quest.questions.length)
    .fun-buttons-container {
      font-size: 16px;
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    .container {
      display: flex;
      flex-direction: column;
    }
    
    .question {
      border: 1px solid #0000FF;
      padding: 1rem;
    }
    
    .question .choices {
      display: flex;
      flex-direction: column;
      padding: 1rem;
    }
    
    .question .choices[data-showhide="show"] {
      background-color: #FFb50011;
    }
    
    .question .choices[data-showhide="blue"] {
      background-color: #0000FF11;
    }
    
    .question .choices[data-showhide="good"] {
      background-color: #00FF0011;
    }
    
    .question .choices[data-showhide="wrong"] {
      background-color: #FF000011;
    }
    
    .question .choices[data-showhide="hide"] {
      display: none;
    }
    
    .woops {
      border: solid 1px red;
      padding: 0.5rem;
    }
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
    
    <div class="fun-buttons-container container-fluid">
    </div>
    
    <template id="questionBlock">
    <div class="question container-fluid">
        <div class="choices" data-showhide="hide">
        <label>Question: <span class="question-text"></span>?</label>
        <select></select>
        </div>
        <button class="btn btn-primary"></button>
    </div>
    </template>
    <template id="errorBlock">
    <div class="woops">&nbsp;hi</div>
    </template>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search