0

I was trying to display questions on html page rather on web dialog box using DOM of javascript but my codes is not working. The program is suppose to loop through the quiz in the js code and ask the questions without using dialog box, show whether the answer is right or wrong on the html page.

Here is the html codes:

var $question = document.getElementById("question");

var $feedback = document.getElementById("feedback");

var $score = document.getElementById("score");

quiz = {
  name: "Super hero name quiz",
  description: "How many super heroes can you name?",

  question: "what is the real name of ",
  questions: [{
      question: "superman",
      answer: "clarke kent"
    },
    {
      question: "batman",
      answer: "bruce wayne"
    },
    {
      question: "wonder woman",
      answer: "dianna prince"
    }
  ]
};



play(quiz);


function update(element, content, klass) {

  var p = element.firstChild ||
    document.createElement("p");

  p.textContent = content;
  element.appendChild("p");
  if (klass) {
    p.className = klass;
  }

}

function play(quiz) {

  var score = 0;
  update($score, score);
  for (i = 0; i < quiz.questions.length; i++) {
    question = quiz.questions[i].question;
    answer = ask(question);
    check(answer);
  }
  gameOver();
}

function check(ans) {

  if (ans === quiz.questions[i].answer) {

    update($feedback, "correct!", "right");
    score++;
    update($score, score);
  } else {
    update($feedback, "Wrong!", "wrong");
  }
}


function ask(question) {

  update($question, quiz.question + question);

  return prompt("Enter your answer: ");
}

function gameOver() {

  update($question, "Game over, you scored" + score + "points");
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="style.css" rel="stylesheet" type="text/css">
</head>

<body>
  <header>
    <h1>QUIZ NINJA!!!</h1>
  </header>
  <section id="question"></section>
  <section id="feedback"></section>
  <p>Score: <strong id="score">0</strong></p>
  <script type="text/javascript" src="chap6_dom.js"></script>
</body>

</html>
kiner_shah
  • 3,939
  • 7
  • 23
  • 37
Ademola
  • 9
  • 3
  • See the console log, you may see some errors. – kiner_shah Jan 02 '22 at 11:07
  • Did you mean `element.appendChild(p);`? `score` is out of scope. See [What is the scope of variables in JavaScript?](/q/500431/4642212) and [Do DOM tree elements with ids become global variables?](/q/3434278/4642212). – Sebastian Simon Jan 02 '22 at 11:56
  • Thanks I've made the score a global variable. but the page is still not bringing anything up – Ademola Jan 02 '22 at 12:15

2 Answers2

0

Please see the comments marked as // CHANGE: in JS code in order to understand the changes done:

var questionSection = document.getElementById("question");

var feedbackSection = document.getElementById("feedback");

var scoreText = document.getElementById("score");

// CHANGE: made score global
var score = 0;
// CHANGE: added var in front of quiz
var quiz = {
  name: "Super hero name quiz",
  description: "How many super heroes can you name?",

  question: "What is the real name of ",
  questions: [{
      question: "superman",
      answer: "clarke kent"
    },
    {
      question: "batman",
      answer: "bruce wayne"
    },
    {
      question: "wonder woman",
      answer: "dianna prince"
    }
  ]
};

// CHANGE: no need to pass quiz, since it's global
play();

function update(element, content, klass) {
  //console.log(element, content, klass);
  var p = element.firstChild || document.createElement("p");

  p.textContent = content;
  // CHANGE: Add the created element p instead of "p"
  element.appendChild(p);
  // CHANGE: check for undefined
  if (klass !== 'undefined') {
    p.className = klass;
  }

}
// CHANGE: added sleep - https://stackoverflow.com/a/39914235/4688321
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
// CHANGE: make play async in order to use sleep after each question (to display the result)
async function play() {
  update(scoreText, score);
  for (i = 0; i < quiz.questions.length; i++) {
    question = quiz.questions[i].question;
    answer = ask(question);
    // CHANGE: pass expected answer as argument
    check(answer, quiz.questions[i].answer);
    await sleep(1000);
  }
  gameOver();
}

function check(actualAns, expectedAns) {

  if (actualAns === expectedAns) {
    update(feedbackSection, "Correct!", "right");
    score++;
    update(scoreText, score);
  } else {
    update(feedbackSection, "Wrong!", "wrong");
  }
}


function ask(question) {
  var fullQuestion = quiz.question + question + "?";
  update(questionSection, fullQuestion);
  // CHANGE: print full question to prompt
  return prompt(fullQuestion + "\nEnter your answer: ");
}

function gameOver() {
  update(questionSection, "Game over, you scored " + score + " points");
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="style.css" rel="stylesheet" type="text/css">
</head>

<body>
  <header>
    <h1>QUIZ NINJA!!!</h1>
  </header>
  <section id="question"></section>
  <section id="feedback"></section>
  <p>Score: <strong id="score">0</strong></p>
  <script type="text/javascript" src="chap6_dom.js"></script>
</body>

</html>
kiner_shah
  • 3,939
  • 7
  • 23
  • 37
0

I had some time to kill and put together this litle script that could potentially handle a number of similar quizes on one page:

const SHQuiz = {
  name:        "Super hero name quiz",
  description: "How many super heroes can you name?",
  question:    "What is the real name of ...",
  questions: [{q:"superman",     a: "clarke kent"},
              {q:"batman",       a: "bruce wayne"},
              {q:"wonder woman", a: "dianna prince"}]
};

function initQuiz(qu) { 
 const Q={...qu,score:0,id:-1}; // create a flat copy of the quiz object
 // utility function appEl: append an element to parent and return the reference to the element
 function appEl(parent){ // parent is a variable in the scope of the returned function:
  return function([type,innerHTML]){
   const el=document.createElement(type);
   el.innerHTML=innerHTML;
   parent.append(el);
   return el;
  }
 } 
 // initialise quiz:
 const qdiv=appEl(document.body),
  [,,,score,main]=[["H2",Q.name],["H4",Q.description],["H3",Q.question],["h4","Score: 0"],["DIV",""]]
   .map(qdiv); // save references of last two elements into the constants score and main
 // ====== event handler function definition =========
 (main.onclick=function(ev){
  // console.log("OK",Q.id);
  // delegated event handling for button clicks only:
  if (ev && ev.target.tagName!=="BUTTON") return false;
  if(Q.id+1) { // check current answer:
   ev.target.style.display="none";
   const ans=ev.target.previousElementSibling;
   ans.readOnly=true;
   if (ans.value.toLowerCase()===Q.questions[Q.id].a) {
     ans.classList.add("correct");
     score.textContent="Score: "+(Q.score+=10);
   }
   else ans.classList.add("wrong");
  }
  const q=Q.questions[++Q.id];
  if(q) { // show next question:
   appEl(main)(["div",`<p>${q.q}</p><input type="text"><button>answer</button>`]).children[1].focus()
  } else score.textContent += " - "+["poor","keep practicing!","not bad","yeah - 100%!"][Q.score/10]
 })() // assign event handler to main element and execute once, without arguments
}

initQuiz(SHQuiz); // start quiz
.correct {color:green}
.wrong   {color:red}
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43