Display data from API as a quiz application

<%= @topic_view.topic.title %>
<%= @topic_view.topic.average_rating %> <%= @topic_view.topic.posts.count { |p| !!p.custom_fields['rating'] } %>

Hi everyone!

Please help me with this exercise! :pray:
As the topic mentioned I got an API link https://opentdb.com/api.php?amount=10 and I have to get the data from that API to make a simple quiz with javascript (yes SIMPLE but I can’t figure out how to do it :cold_sweat: difficult for me). So far my code look like this:

HTML

Challenge Quiz

Challenge Your Brain!

<div id="quiz"></div>
<button id="submit">Submit Quiz</button>
<div id="results"></div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="../JS/quizapplikation-script.js"></script>

… And JS

var url = ‘https://opentdb.com/api.php?amount=10’;
var currentQuestion = 0;

$.getJSON(url, function (data) {
var myQuestions = data.results;

for (let i = 0; i < myQuestions.length; i++) {
    var question = myQuestions[i].question;
    var correctAnswer = myQuestions[i].correct_answer;
    var incorrectAnswers = myQuestions[i].incorrect_answers;
    var totAnswers = {
        correctAnswer,
        incorrectAnswers
    };
    console.log(incorrectAnswers);
}

function buildQuiz() {
    const output = [];

    myQuestions.forEach((currentQuestion, questionNumber) => {
            const answers = [];

            for (letter in currentQuestion.totAnswers) {
                answers.push(
                  `<label>
                    <input type="radio" name="question${questionNumber}" value="${letter}">
                    ${letter} :
                    ${currentQuestion.totAnswers[letter]}
                  </label>`
                );
              }
            output.push(
              `<div class="slide">
                 <div class="question"> ${currentQuestion.question} </div>
                 <div class="answers"> ${totAnswers.join("")} </div>
               </div>`
            );
          });

quizContainer.innerHTML = output.join("");

}

function showResults() {
const answerContainers = quizContainer.querySelectorAll(".answers");

let numCorrect = 0;

myQuestions.forEach((currentQuestion, questionNumber) => {
    const answerContainer = answerContainers[questionNumber];
    const selector = `input[name=question${questionNumber}]:checked`;
    const userAnswer = (answerContainer.querySelector(selector) || {}).value;


    if (userAnswer === currentQuestion.correctAnswer) {
        numCorrect++;

        answerContainers[questionNumber].style.color = "lightgreen";
    } else {
        answerContainers[questionNumber].style.color = "red";
    }
});

resultsContainer.innerHTML = `${numCorrect} out of ${myQuestions.length}`;

}

const quizContainer = document.getElementById(“quiz”);
const resultsContainer = document.getElementById(“results”);
const submitButton = document.getElementById(“submit”);

buildQuiz();

submitButton.addEventListener(“click”, showResults);
})

The problem is I can’t make the answer to showed upp.

As you can see, the questions do appear but not the answers. It looks weird! I don’t understand why? where did I do wrong?

Thanks in advance!
Tho

The default conversion from an Object to a string is [object Object] thanks to the toString() method.

This means you are trying to print an object into the page, instead of its values/keys.

You could JSON.stringify it, or look for its keys or values. That’s up to you :slight_smile:

Thanks for your tips! I did figure out the problem by myself later :grinning:. But there is still an erro that I do not know how to resolve. I put all the answer together to an array and then use the loop to print out the answers for each question. But there are 10 questions and I got only one array of answers for all of them. It looks like this:

I know that the problem is where I use the loop for the totAnswers variable. But I don’t understand why. I’m stuck!

Here is my code for now, I edited it a bit.

var url = ‘https://opentdb.com/api.php?amount=10’;

$.getJSON(url, function (data) {
var myQuestions = data.results;

for (question of myQuestions) {
    var correctAnswer = question.correct_answer;
    var totAnswers = question.incorrect_answers;
    totAnswers.push(correctAnswer);
    // console.log(totAnswers);
}

function buildQuiz() {
    const output = [];
    myQuestions.forEach((currentQuestion, questionNumber) => {
        const answers = [];
        //PROBLEM HERE, WHEN I CONSOLE.LOG(totAnswers), IT COMES OUT 10 //ARRAY WITH THE ANSWERS BUT IT ALL THE SAME, IT SHOULD BE 10 DIFFERENT //ARRAY WITH DIFFERENT ANSWERS
        for (value of totAnswers) {
            console.log(totAnswers);
            answers.push(
              `<label>
                <input type="radio" name="question${questionNumber}" value="${value}">
                ${value} 
              </label>`
            );
          }

        output.push(
            `<div class="slide">
                   <div class="question"> ${currentQuestion.question} </div>
                   <div class="answers"> ${answers.join("")} </div>
                 </div>`
        );
    });
    quizContainer.innerHTML = output.join('');
}

If you have time, please point out some tips to help me, I’ll be really grateful for that :heart_eyes:

It’s pretty hard just by looking at the code, a demo would certainly be more helpful.

However just by looking at this segment I can guess you are always printing the last question since in your loop you overwrite the same variable instead of adding into a new dataset.

for (question of myQuestions) {
    var correctAnswer = question.correct_answer;
    var totAnswers = question.incorrect_answers;
    totAnswers.push(correctAnswer);
}

// outside here totAnswer holds only the last value iterate

I Imagine your goal is to have an array that contains all the answers for the given question, like

[ [answer 1 ] [answer 2 ] ...ecc ..ecc]

You can simply add your formatted answer into a new data structure

let allTheAnswers = []
for (question of myQuestions) {
    var correctAnswer = question.correct_answer;
    var totAnswers = question.incorrect_answers;
    totAnswers.push(correctAnswer);
    // append totAnswers to all answers 
    allTheAnswers = [...allTheAnswers, totAnswers]
}

// totAnswers is still the last iteration
// however allTheAnswers now contains all the answers looped so far

Hope this helps :+1:

1 Like

Thanks! I will try it out :smiley:

@ThoTr Do you have the full final code to show? I’m working on a similar quiz and want to see the outcome of your code.