Ive been trying to learn Javascript OOP so i made a quiz. However for some reason my html is not being populated with the questions and answers I made. I cannot figure out the problem. Any help would be greatly appreciated!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Edgy Quiz</title>
<link type="text/css" rel="stylesheet" href="style.css"/>
</head>
<body>
<h1>In a world where everyone is looking to stand out from the crowd</h1>
<h2>Does the extend of your own edginess confuse you?</h2>
<h3>Well this scientifically proven personality test was built for you!</h3>
<div class="grid">
<div id="quiz">
<h4>How edgy are you?</h4>
<hr style="margin-top: 20px">
<p id="question"></p>
<div class="buttons">
<button id="btn0"><span id="choice0"></span></button>
<button id="btn1"><span id="choice1"></span></button>
<button id="btn2"><span id="choice2"></span></button>
<button id="btn3"><span id="choice3"></span></button>
</div>
<hr style="margin-top: 50px">
<footer>
<p id="progress">Question x of y.</p>
</footer>
</div>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
$(window).load(function() {
function Question(text, choices, answer) {
this.text = text;
this.choices = choices;
this.answer = answer;
}
Question.prototype.correctAnswer = function(choice) {
return choice === this.answer;
}
function Quiz(questions) {
this.score = 0;
this.questions = questions;
this.questionIndex = 0;
}
Quiz.prototype.getQuestionIndex = function() {
return this.questions[this.questionIndex];
}
Quiz.prototype.isEnded = function() {
return this.questions.length === this.questionIndex;
}
Quiz.prototype.guess = function(answer) {
if (this.getQuestionIndex().correctAnswer(answer)) {
this.score++;
}
this.questionIndex++;
}
function populate() {
if(quiz.isEnded()) {
showScores();
}
else {
var element = document.getElementById("question");
element.innerHTML = quiz.getQuestionIndex().text;
var choices = quiz.getQuestionIndex().choices;
for(var i = 0; i < choices.length; i++) {
var element = document.getElementById("choice" + i);
element.innerHTML = choices[i];
guess("btn" + i, choices[i]);
}
showProgress();
}
}
function guess(id, guess) {
var button = document.getElementById(id);
button.onclick = function () {
quiz.guess(guess);
populate();
}
}
function showProgress () {
var currentQuestionNumber = quiz.questionIndex + 1;
var element = document.getElementById("progress");
element.innerHTML = "Question " + currentQuestionNumber + "of " +
quiz.questions.length;
}
function showScores() {
var gameOverHtml = "<h1>Result</h1>";
gameOverHtml += "<h2 id='score'>Your score: ' + quiz.score + '</h2>";
var element = document.getElementById("quiz");
element.innerHTML = gameOverHtml;
}
var questions = [
new Question ("How have you discovered this test?", ["I was bored browsing
online", "I want to see how edgy I am", "Im a friend doing it out of
Sympathy", "Im looking at this weirdo's portfolio"], "Im looking at this
weirdo's portfolio"),
new Question ("How edgy do you think you are?", ["Extremely edgy", "Im very
mainstream", "What does edgy even mean?", "I don't do labels"], "I don't do
labels"),
new Question ("Of these colors which is your favourite?", ["Blue", "Orange",
"Majenta", "Black"], ""),
new Question ("Could you bring yourself to hurt a living thing?", ["Only if
it hurt me first", "I hurt stuff for fun", "No never how could you im a
vegan", "I hurt myself all the time"], "I hurt myself all the time"),
new Question ("If someone tickled you how would you respond?", ["Tickle
fight", "Run away", "Punch them in the face", "Write a song"], "Write a
song"),
];
var quiz = new Quiz(questions);
populate();
});
Related
I am wanting to create a button, and when it is pressed it will 'type' out some random text. I've followed many tutorials/code snippets with no luck in getting the implementation right.
Essentially, I want to combine these two scripts. When I click a button it should choose a random string and then use the 'typing' effect to type it.
Pressing the button again will interrupt whatever is being typed, and generate new text.
Any help is really appreciated!
var i = 0;
var txt = 'Lorem ipsum dummy text.';
var speed = 50;
function typeWriter() {
if (i < txt.length) {
document.getElementById("demo").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
}
}
<button onclick="typeWriter()">Click me</button>
<p id="demo"></p>
and this:
var quotes = [
'The sky is blue',
'The stove is hot',
'The floor is wet',
'The grass is green',
'The water is cold'
]
function newQuote() {
var randomNumber = Math.floor(Math.random() * (quotes.length));
document.getElementById('quoteDisplay').innerHTML = quotes[randomNumber];
}
<div id="quoteDisplay"></div>
<button onclick="newQuote()">Click me</button>
you almost there
var i = 0;
var txt = ''; //the typing text
var speed = 50;
function typeWriter() {
//clear the html initially for a text
if (i === 0)
document.getElementById("demo").innerHTML = '';
if (i < txt.length) {
document.getElementById("demo").innerHTML += txt.charAt(i);
i++;
setTimeout(typeWriter, speed);
}
}
var quotes = [
'The sky is blue',
'The stove is hot',
'The floor is wet',
'The grass is green',
'The water is cold'
]
function newQuote() {
//set the typing text
txt = quotes[Math.floor(Math.random() * quotes.length)];
//reset the index
i = 0;
typeWriter();
}
<button onclick="newQuote()">Click me</button>
<p id="demo"></p>
Here we go:
var i = 0;
var speed = 50;
var timeoutId;
var quotes = [
'The sky is blue',
'The stove is hot',
'The floor is wet',
'The grass is green',
'The water is cold'
]
function newQuote() {
document.getElementById("quoteDisplay").innerHTML = ""
var randomNumber = Math.floor(Math.random() *(quotes.length));
txt = quotes[randomNumber];
if (timeoutId) clearTimeout(timeoutId);
i = 0;
typeWriter(txt)
}
function typeWriter(txt) {
if (i < txt.length) {
document.getElementById("quoteDisplay").innerHTML += txt.charAt(i);
i++;
timeoutId = setTimeout(typeWriter, speed, txt);
}
}
<div id="quoteDisplay"></div>
<button onclick="newQuote()">Click me</button>
let i = 0;
let randomNumber;
let speed = 50;
let clickBtn = document.querySelector("#click");
let quotes = [
"The sky is blue",
"The stove is hot",
"The floor is wet",
"The grass is green",
"The water is cold"
];
const typeWriter = () => {
if (i === 0) {
document.getElementById("demo").innerHTML = '';
}
if (i < quotes[randomNumber].length) {
document.getElementById("demo").innerHTML += quotes[randomNumber].charAt(i);
i++;
setTimeout(typeWriter, speed);
}
};
clickBtn.addEventListener("click", () => {
i = 0
randomNumber = Math.floor(Math.random() * quotes.length);
typeWriter();
});
You should use setInterval instead:
/* js/external.js */
//<![CDATA[
var doc, bod, I, TypeMaker; // for use on other loads
addEventListener('load', function(){
doc = document; bod = doc.body;
I = function(id){
return doc.getElementById(id);
}
TypeMaker = function(element, interval){
this.element = element; this.interval = interval || 50;
var t = this, r;
this.type = function(string){
if(r)clearInterval(r);
var s = string.split(''), l = s.length, i = 0;
var p = 'value' in this.element ? 'value' : 'innerHTML';
this.element[p] = '';
r = setInterval(function(){
t.element[p] += s[i++];
if(i === l){
clearInterval(r); r = undefined;
}
}, t.interval);
}
}
var typer = new TypeMaker(I('output')), single_test = I('single_test'), rand_test = I('rand_test');
var testArray = ['The sky is blue.', 'The stove is hot.', 'The floor is wet.', 'The grass is green.', 'The water is cold.'];
var testArrayL = testArray.length;
single_test.onclick = function(){
typer.type('Lorem ipsum dummy text.');
}
rand_test.onclick = function(){
typer.type(testArray[Math.floor(Math.random()*testArrayL)]);
}
});
//]]>
/* css/external.css */
*{
box-sizing:border-box; padding:0; margin:0;
}
input{
padding:3px 5px;
}
#output{
display:inline-block; margin-left:7px;
}
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta charset='UTF-8' /><meta name='viewport' content='width=device-width, height=device-height, initial-scale:1' />
<title>Test Template</title>
<link type='text/css' rel='stylesheet' href='css/external.css' />
<script type='text/javascript' src='js/external.js'></script>
</head>
<body>
<input id='single_test' type='button' value='test' />
<input id='rand_test' type='button' value='random' />
<div id='output'></div>
</body>
</html>
The project I am working on originally consisted of a single quiz that asked five questions and at the end it will tell you your score and that is it. I am learning more about the MVC model and so it was built using that model.
Now I want to add new features to the quiz app such as if you get a score greater than three the final page with a score with have a button that says "level 2" as in the image below and when you click on it it takes you to the next level with a new set of questions from another object:
If you score less than three you get a button that will say "try again" and the quiz restarts. If you move on to the next level I want the score to be kept and the same process will take place until you reach the third level.
The issue I am having is trying to figure out how to reuse the same code to repopulate the page with a new set of questions for the next level and to keep track of the score. I tried to create a new method called nextLevel that when you click the level two button the quiz will repopulate with the new questions but that is not happening. Any help or guidance would be appreciated.
Here is my index.html:
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Capstone</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="grid">
<div id="quiz">
<h1>JerZey's</h1>
<hr style="margin-bottom: 20px">
<p id="question"></p>
<div class="buttons">
<button id="btn0"><span id="choice0"></span></button>
<button id="btn1"><span id="choice1"></span></button>
<button id="btn2"><span id="choice2"></span></button>
<button id="btn3"><span id="choice3"></span></button>
</div>
<div id="btn5">
</div>
<hr style="margin-top: 50px">
<footer>
<p id="progress">Question x of y</p>
</footer>
</div>
</div>
<script src="quiz.js"></script>
<script src="question.js"></script>
<script src="app.js"></script>
</body>
</html>
Here is my model(question.js):
function Quiz(questions) {
this.score = 0;
this.questions = questions;
this.questionIndex = 0;
}
Quiz.prototype.getQuestionIndex = function() {
return this.questions[this.questionIndex];
}
Quiz.prototype.guess = function(answer) {
if(this.getQuestionIndex().isCorrectAnswer(answer)) {
this.score++;
}
this.questionIndex++;
}
Quiz.prototype.isEnded = function() {
return this.questionIndex === this.questions.length;
}
Controller (quiz.js):
function Quiz(questions) {
this.score = 0;
this.questions = questions;
this.questionIndex = 0;
}
Quiz.prototype.getQuestionIndex = function() {
return this.questions[this.questionIndex];
}
Quiz.prototype.guess = function(answer) {
if(this.getQuestionIndex().isCorrectAnswer(answer)) {
this.score++;
}
this.questionIndex++;
}
Quiz.prototype.isEnded = function() {
return this.questionIndex === this.questions.length;
}
Views(app.js):
function populate() {
if(quiz.isEnded()) {
showScores();
}
else {
// show question
var element = document.getElementById("question");
element.innerHTML = quiz.getQuestionIndex().text;
// show options
var choices = quiz.getQuestionIndex().choices;
for(var i = 0; i < choices.length; i++) {
var element = document.getElementById("choice" + i);
element.innerHTML = choices[i];
guess("btn" + i, choices[i]);
}
showProgress();
}
};
function guess(id, guess) {
var button = document.getElementById(id);
button.onclick = function() {
quiz.guess(guess);
populate();
}
};
function showProgress() {
var currentQuestionNumber = quiz.questionIndex + 1;
var element = document.getElementById("progress");
element.innerHTML = "Question " + currentQuestionNumber + " of " + quiz.questions.length;
};
function showScores() {
if(quiz.score < 3){
var gameOverHTML = "<h1>Level 1 Complete</h1>";
gameOverHTML += "<h2 id='score'> Your scores: " + quiz.score + "</h2><button onClick='refreshPage()' type='button'>Try Again</button>";
var element = document.getElementById("quiz");
element.innerHTML = gameOverHTML;
}else{
var gameOverHTML = "<h1>Level 1 Complete</h1>";
gameOverHTML += "<h2 id='score'> Your scores: " + quiz.score + "</h2><button type='button' onClick='nextLevel()'>Level 2</button>";
var element = document.getElementById("quiz");
element.innerHTML = gameOverHTML;
}
};
function refreshPage() {
location.reload();
};
function nextLevel(){ //This is where I am stuck at and am not sure if I even need it or if I am going about it the wrong way
var quiz = new Quiz(questions2);
populate();
};
// find a way to show countdown on screen
// setInterval(showScores, 5000);
// create questions
var questions = [
new Question("What two teams have been active since 1920?", ["New York Giants and Dallas Cowboys", "Denver Broncos and Oakland Raiders","Arizona Cardinals and Chicago Bears", "Green Bay Packers and Detroit Lions "], "Arizona Cardinals and Chicago Bears"),
new Question("What team has 216 games played?", ["Houston Texans", "Los Angeles Chargers", "Miami Dolphins", "Washington Redskins"], "Houston Texans"),
new Question("What's the correct number of the Oakland Raiders Post-season record of wins?", ["17", "34","100", "25"], "25"),
new Question("Which team has the colors yellow and green?", ["49ers", "Rams", "Packers", "Vikings"], "Packers"),
new Question("What was Kansas City Chiefs regular season record ties?", ["67", "12", "10", "30"], "12")
];
var questions2 = [
new Question("Which team hired their 1st professional cheerleading squad?", ["Dallas Cowboys", "San Francisco 49ers","Tampa Bay Buccaneers", "Chicago Bears "], "Dallas Cowboys"),
new Question("What team won the first final in January 1967?", ["Houston Texans", "Los Angeles Chargers", "Miami Dolphins", "Greenbay Packers"], "Greenbay Packers"),
new Question("Who won the most superbowls in history?", ["Steelers", "Redskins","Lions", "Seahawks"], "Steelers"),
new Question("The curse of 10 which NFL team has only scored 10 points in 3 different superbowls?", ["Raiders", "Rams", "Broncos", "Vikings"], "Broncos"),
new Question("How many rings does Tom Brady have?", ["4", "1", "3", "5"], "5")
];
var questions3 = [
new Question("What were Nfl players required to wear in games for the 1st time in 1943?", ["Knee pads", "Bandanas","Helmets", "Raider Jerseys "], "Helmets"),
new Question("What was the Nfl's sports caster Madden's first name ?", ["Derek", "John", "Anthony", "Bob"], "John"),
new Question("How many years do players have to be retired to be eligible for the Hall of Fame", ["10", "2","7", "5"], "5"),
new Question("Where were the Rams originally franchised before they moved to Los Angeles?", ["Cleveland", "Atlanta", "Detroit", "New York"], "Cleveland"),
new Question("Which Nfl team features a helmet decal only on one side?", ["Eagles", "Saints", "Jaguars", "Steelers"], "Steelers")
];
// create quiz
var quiz = new Quiz(questions);
// display quiz
populate();
Here is what the quiz looks like when you lose:
Here is what it looks like in the beginning:
Interesting exercise. To adhere as closely to MVC as possible, I would implement it as follows.
You instantiate your model and your view, and pass them to the controller, in your main app section, then leave the controller to "control" the view and the model.
I have left out the handling of difficulty levels, but it should be pretty clear where that fits.
Model.js
function Question(text, choices, answer) {
this.text = text;
this.choices = choices;
this.answer = answer;
}
Question.prototype.hasAnswer = function (answer) {
return this.answer === answer;
};
function Model(questions) {
this.questions = questions;
this.questionIndex = 0;
this.score = 0;
}
Model.prototype.nextQuestion = function () {
if (this.questionIndex < this.questions.length)
return this.questions[this.questionIndex];
return null;
};
Model.prototype.checkAnswer = function (choice) {
if (this.questions[this.questionIndex].hasAnswer(choice))
this.score++;
this.questionIndex++;
};
Model.prototype.reset = function () {
this.questionIndex = 0;
this.score = 0;
};
Controller.js
function Controller(doc, model) {
this.doc = doc;
this.model = model;
}
Controller.prototype.initialize = function () {
this.next();
};
Controller.prototype.next = function () {
const that = this;
const question = this.model.nextQuestion();
if (question == null) {
this.showScore();
return;
}
const questionSection = this.doc.querySelector("#question");
questionSection.innerHTML = question.text;
const choicesSection = this.doc.querySelector("#choices");
choicesSection.innerHTML = "";
for (let choice of question.choices) {
const choiceButton = this.doc.createElement("button");
choiceButton.innerHTML = choice;
choiceButton.addEventListener("click", function (e) {
that.model.checkAnswer(choice);
that.next();
});
choicesSection.append(choiceButton);
}
};
Controller.prototype.showScore = function () {
const that = this;
this.clear();
const scoreSection = this.doc.querySelector("#score");
scoreSection.innerHTML = "Score: " + this.model.score;
const tryAgainButton = this.doc.createElement("button");
tryAgainButton.innerHTML = "Try again";
tryAgainButton.addEventListener("click", function (e) {
scoreSection.innerHTML = "";
that.model.reset();
that.next();
});
scoreSection.append(this.doc.createElement("p"));
scoreSection.append(tryAgainButton);
};
Controller.prototype.clear = function () {
const questionSection = this.doc.querySelector("#question");
questionSection.innerHTML = "";
const choicesSection = this.doc.querySelector("#choices");
choicesSection.innerHTML = "";
};
Index.html (view)
<!DOCTYPE html>
<html>
<head>
<title>Quizaaaaaaaaaaaaaaaaaaaaa</title>
<script type="text/javascript" src="model.js"></script>
<script type="text/javascript" src="controller.js"></script>
<script type="text/javascript">
window.addEventListener("load", function (e) {
const questions = [
new Question("Question A", ["A", "B", "C", "D"], "A"),
new Question("Question B", ["A", "B", "C", "D"], "B"),
new Question("Question C", ["A", "B", "C", "D"], "C"),
new Question("Question D", ["A", "B", "C", "D"], "D")
];
const model = new Model(questions);
const controller = new Controller(document, model);
controller.initialize();
});
</script>
</head>
<body>
<div id="question"></div>
<div id="choices"></div>
<div id="score"></div>
</body>
</html>
I am going through this JavaScript tutorial and ran into an issue that I hope someone can assist me with. After selecting the last question on the quiz, my showScore() function displays the results as "undefined". Through some further debugging, I found that it was a problem with my quiz object. In my PopulateQuestion() function, I am able to print out the quiz object before executing the showScore() function. However, when I attempt to print out the quiz object from within the showScore() function, it returns undefined.
I would like to work on my ability to debug issues that come up like this. Based on debugging that I have done so far, my educated guess is that this is a scope issue, but I am stuck. Does anyone have any suggestions for debugging this further?
Here is my code
Index.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>JS Quiz</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="quiz-container">
<div id="quiz">
<h1>Star Wars Quiz</h1>
<hr style="margin-top: 20px;" />
<p id="question">Who is Darth Vader?</p>
<div class="buttons">
<button id="b0"><span id="c0"></span></button>
<button id="b1"><span id="c1"></span></button>
<button id="b2"><span id="c2"></span></button>
<button id="b3"><span id="c3"></span></button>
</div>
<hr style="margin-top: 50px" />
<footer>
<p id="progress">Question x of n</p>
</footer>
</div>
</div>
<script src="quiz-controller.js"></script>
<script src="question.js"></script>
<script src="app.js"></script>
</body>
</html>
app.js
function populateQuestion() {
if(quiz.isEnded()) {
// display score
console.log(quiz);
showScore();
} else {
// display question
var qElement = document.getElementById('question');
qElement.innerHTML = quiz.getCurrentQuestion().text;
// display choices
var choices = quiz.getCurrentQuestion().choices;
for(var i = 0; i < choices.length; i++) {
var choice = document.getElementById('c' + i);
choice.innerHTML = choices[i];
guess("b" + i, choices[i]);
}
showProgress();
}
}
function guess(id, guess) {
var button = document.getElementById(id);
button.onclick = function() {
quiz.guess(guess);
populateQuestion();
};
}
function showProgress() {
var currentQuestionNum = quiz.questionIndex + 1;
var progress = document.getElementById("progress");
progress.innerHTML = "Question " + currentQuestionNum + " of " + quiz.questions.length;
}
function showScore() {
console.log(quiz);
var resultsHTML = "<h1>Results</h1>";
resultsHTML += "<h2 id='score'>Your Score: " + quiz.getScore() + "</h2>";
var quiz = document.getElementById("quiz");
quiz.innerHTML = resultsHTML;
}
var questions = [
new Question("Who is Darth Vader?",
["Luke Skywalker", "Anakin Skywalker", "Your Mom", "Your Dad"],
"Anakin Skywalker"),
new Question("What is the name of the third episode?",
["Return of the Jedi", "Revenge of the Sith", "A New Hope", "The Empire Strikes Back"],
"Revenge of the Sith"),
new Question("Who is Anakin Skywalker's son?",
["Luke Skywalker", "Anakin Skywalker", "Your Mom", "Your Dad"],
"Luke Skywalker"),
new Question("What is the name of the sixth episode?",
["Return of the Jedi", "Revenge of the Sith", "A New Hope", "The Empire Strikes Back"],
"Return of the Jedi")
];
var quiz = new Quiz(questions);
populateQuestion();
question.js
function Question(text, choices, answer) {
this.text = text;
this.choices = choices;
this.answer = answer;
}
Question.prototype.correctAnswer = function(choice) {
return choice === this.answer;
};
quiz-controller.js
function Quiz(questions) {
this.score = 0;
this.questionIndex = 0;
this.questions = questions;
}
Quiz.prototype.getScore = function() {
return this.score;
};
Quiz.prototype.getCurrentQuestion = function() {
return this.questions[this.questionIndex];
};
Quiz.prototype.isEnded = function() {
return this.questionIndex === this.questions.length;
};
Quiz.prototype.guess = function(answer) {
if(this.getCurrentQuestion().correctAnswer(answer)) {
this.score++;
}
this.questionIndex++;
};
Your problem is that in the showScore() function you define a local variable with the name quiz. This local variable hides the global variable with the same name (even though it is defined later in the code).
You can easily fix that by renaming your local variable in showScore (below shown as q instead of quiz):
function populateQuestion() {
if(quiz.isEnded()) {
// display score
console.log(quiz);
showScore();
} else {
// display question
var qElement = document.getElementById('question');
qElement.innerHTML = quiz.getCurrentQuestion().text;
// display choices
var choices = quiz.getCurrentQuestion().choices;
for(var i = 0; i < choices.length; i++) {
var choice = document.getElementById('c' + i);
choice.innerHTML = choices[i];
guess("b" + i, choices[i]);
}
showProgress();
}
}
function guess(id, guess) {
var button = document.getElementById(id);
button.onclick = function() {
quiz.guess(guess);
populateQuestion();
};
}
function showProgress() {
var currentQuestionNum = quiz.questionIndex + 1;
var progress = document.getElementById("progress");
progress.innerHTML = "Question " + currentQuestionNum + " of " + quiz.questions.length;
}
function showScore() {
console.log(quiz);
var resultsHTML = "<h1>Results</h1>";
resultsHTML += "<h2 id='score'>Your Score: " + quiz.getScore() + "</h2>";
var q = document.getElementById("quiz");
q.innerHTML = resultsHTML;
}
var questions = [
new Question("Who is Darth Vader?",
["Luke Skywalker", "Anakin Skywalker", "Your Mom", "Your Dad"],
"Anakin Skywalker"),
new Question("What is the name of the third episode?",
["Return of the Jedi", "Revenge of the Sith", "A New Hope", "The Empire Strikes Back"],
"Revenge of the Sith"),
new Question("Who is Anakin Skywalker's son?",
["Luke Skywalker", "Anakin Skywalker", "Your Mom", "Your Dad"],
"Luke Skywalker"),
new Question("What is the name of the sixth episode?",
["Return of the Jedi", "Revenge of the Sith", "A New Hope", "The Empire Strikes Back"],
"Return of the Jedi")
];
function Question(text, choices, answer) {
this.text = text;
this.choices = choices;
this.answer = answer;
}
Question.prototype.correctAnswer = function(choice) {
return choice === this.answer;
};
function Quiz(questions) {
this.score = 0;
this.questionIndex = 0;
this.questions = questions;
}
Quiz.prototype.getScore = function() {
return this.score;
};
Quiz.prototype.getCurrentQuestion = function() {
return this.questions[this.questionIndex];
};
Quiz.prototype.isEnded = function() {
return this.questionIndex === this.questions.length;
};
Quiz.prototype.guess = function(answer) {
if(this.getCurrentQuestion().correctAnswer(answer)) {
this.score++;
}
this.questionIndex++;
};
var quiz = new Quiz(questions);
populateQuestion();
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>JS Quiz</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="quiz-container">
<div id="quiz">
<h1>Star Wars Quiz</h1>
<hr style="margin-top: 20px;" />
<p id="question">Who is Darth Vader?</p>
<div class="buttons">
<button id="b0"><span id="c0"></span></button>
<button id="b1"><span id="c1"></span></button>
<button id="b2"><span id="c2"></span></button>
<button id="b3"><span id="c3"></span></button>
</div>
<hr style="margin-top: 50px" />
<footer>
<p id="progress">Question x of n</p>
</footer>
</div>
</div>
<script src="quiz-controller.js"></script>
<script src="question.js"></script>
<script src="app.js"></script>
</body>
</html>
There is private variable quiz in showScore
function which is getting hoisted to the top of the
function as follows:
Your code:
function showScore() {
console.log(quiz);
var resultsHTML = "<h1>Results</h1>";
resultsHTML += "<h2 id='score'>Your Score: " + quiz.getScore() + "</h2>";
var quiz = document.getElementById("quiz");
What internally happens:
function showScore() {
var quiz = undefined; // hoisting is happening here. So quiz is not reffering to public quiz variable anymore.
console.log(quiz);
var resultsHTML = "<h1>Results</h1>";
resultsHTML += "<h2 id='score'>Your Score: " + quiz.getScore() + "</h2>";
var quiz = document.getElementById("quiz");
I am new to the programming world and have been working on a trivia-game style project. The problem I am encountering is as follows: "Uncaught ReferenceError: answer is not defined at HTMLButtonElement.button.onclick".
My question is as follows: How are my question answers not being stored when pressing an answer and what is a better way to define answer in my code? Any help would greatly be appreciated.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Trivia Game</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css" />
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<link href="https://fonts.googleapis.com/css?family=Lora" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="assets/css/style.css" />
</head>
<body>
<div class="grid">
<div id="trivia">
<h1>A Golfer's Trivia</h1>
<!-- for question -->
<div id="questionName">
<p id="question"></p>
</div>
<p id="progress"></p>
<!-- options for the questions -->
<div class="buttons">
<button id="btn0"><span id="option0"></span></button>
<button id="btn1"><span id="option1"></span></button>
<button id="btn2"><span id="option2"></span></button>
<button id="btn3"><span id="option3"></span></button>
</div>
<div>
<p id="timer"></p>
<p id="show-clock"></p>
</div>
</div>
</div>
<script type="text/javascript" src="assets/javascript/game.js"></script>
</body>
</html>``
JAVASCRIPT
// Keeping score
var unanswered = 0;
var questionIndex = 0;
var score = 0;
var questions = 0;
var answer;
function Quiz(questions) {
this.score = 0;
this.questions = questions;
this.questionIndex = 0;
}
function getQuestionIndex() {
return this.questions[this.questionIndex];
}
function endGame() {
return this.questions.length === this.questionIndex;
}
function guess(answer) {
if (this.getQuestionIndex() === correctAnswer(answer)) {
this.score++;
}
this.questionIndex++;
}
// functions for questions
function Question(text, choices, answer) {
this.text = text;
this.choices = choices;
this.answer = answer;
}
// check user answer
function correctAnswer(choice) {
return choice === this.answer;
}
// have questions appear if game is still going
function populate() {
console.log("populating");
if (endGame()) {
showScores();
}
else {
var element = document.getElementById("question");
element.innerHTML = getQuestionIndex().text;
// have options appear for each question
var choices = getQuestionIndex().choices;
for (var i = 0; i < choices.length; i++) {
var element = document.getElementById("option" + i);
element.innerHTML = choices[i];
guess("btn" + i, choices[i]);
}
showProgress()
}
}
// store user guess
function guess(id) {
var button = document.getElementById(id);
button.onclick = function () {
questionIndex++;
populate();
guess(answer);
}
}
// show which question player is on
function showProgress() {
var currentQuestionNumber = questionIndex + 1;
var element = document.getElementById("progress");
element.innerHTML = "Question " + currentQuestionNumber + " of " + questions.length;
}
// display scores at end of game
function showScores() {
var gameOver = "<h1>Results</h1>" + "<h2 class='corr score'> Correct Answers: " + score + "<h2>" + "<br>" + "<h2 class = 'wrong score'>Wrong Answers: " + (questions.length - score) + "<h2 class = 'unanswered score'>Unanswered: " + "<h2>";
var results = document.getElementById("trivia");
results.innerHTML = gameOver;
}
// sets of questions, options, answers
var questions = [
new Question("Where was the game of golf originally founded?",
["Scotland", "China", "England", "United States"],
"Scotland"),
new Question("Who is the only female golfer to make a cut at a PGA Tour event?",
["Michelle Wie", "Annika Sorensteim", "Lexi Thompson", "Babe Zaharias"],
"Babe Zaharias"),
new Question("What is the name for a hole-in-one on a par five?",
["Triple Eagle", "Double Ace", "Condor", "Albatross"],
"Condor"),
new Question("Who holds the record for the most PGA Tour victories?",
["Tiger Woods", "Jack Nicklaus", "Ben Hogan", "Sam Snead"],
"Sam Snead"),
new Question("What percentage of golfers will never achieve a handicap of 18 or less?",
["50 percent", "73 percent", "80 percent", "91 percent"],
"80 percent"),
new Question("How many dimples are on a standard regulation golf ball?",
["336", "402", "196", "468"],
"336"),
new Question("Who was considered the first professional golfer in history?",
["Bobby Jones", "Byron Nelson", "Walter Hagen", "Old Tom Morris"],
"Walter Hagen"),
new Question("Who is the youngest player to win the Masters?",
["Tiger Woods", "Jack Nicklaus", "Jordan Speith", "Arnold Palmer"],
"Tiger Woods")
];
populate();
var intervalId;
$("#btn").on("click", run);
// The run function sets an interval
function run() {
clearInterval(intervalId);
}
var timeLeft = 10;
var displayClock = document.getElementById('timer');
var timerId = setInterval(countdown, 1000);
function countdown() {
if (timeLeft === 0) {
unanswered++;
questionIndex++;
populate();
alert("You did not answer in time!");
timeLeft = 10;
// reset timer, pull question
run();
} else {
displayClock.innerHTML = timeLeft + ' seconds remaining';
timeLeft--;
}
}
run();
I guess you're facing another problem here. Here are 2 functions taken off your script:
guess(any) version 1
function guess(answer) {
if (this.getQuestionIndex() === correctAnswer(answer)) {
this.score++;
}
this.questionIndex++;
}
guess(any)version 2
function guess(id) {
var button = document.getElementById(id);
button.onclick = function () {
questionIndex++;
populate();
guess(answer);
}
}
You have 2 of a function named guess(). Although the names of both values vary, from Javascript's standpoint they both look like this:
function guess(value){}
How is JS supposed to know which of them you intend to call?
Rename at least one of them in order to having total unambiguousness among your function names. And try again.
I'm working through How to Learn JavaScript Correctly. About halfway through it has you create a quiz application. I'm able to get it to display the first question, then clicking the next button changes to the second question. But the problem is that when I click the button a third time, the screen clears and the third question never appears.
I'm sure I'm missing something easy. Any idea where I'm going wrong?
app.js:
var allQuestions = [
{question: "Who is Prime Minister of the United Kingdom?",
choices: ["David Cameron", "Gordon Brown", "Winston Churchill", "Tony Blair"],
correctAnswer:0},
{question: "Who is President of the United States?",
choices: ["George Bush", "Barack Obama", "Hilary Clinton"],
correctAnswer:1},
{question: "What is the best state?",
choices: ["Iowa", "Wisconsin", "Colorado", "North Carolina"],
correctAnswer:1}
];
var score = 0;
var i = 0;
$(document).ready(function() {
$('#next').addClass('hidden');
nextQuestion();
});
function nextQuestion() {
var container = $('#container');
var questionName = allQuestions[i].question
var answer = allQuestions[i].correctAnswer;
var choice = 0;
var question = "<div>" + questionName + "</div>";
container.append(question + "<br>");
var choices = allQuestions[i].choices;
for (var j=0;j<choices.length;j++) {
var choice = choices[j];
var radio = "<input type='radio' data-choice='" + j + "' value='" + choice + "' name='" + allQuestions[i].question + "'>" + choices[j];
container.append(radio + "<br>");
}
$('input:radio').on('click',function() {
choice = $(this).data("choice");
$('#next').removeClass('hidden');
});
$('#next').on('click',function() {
$('#next').addClass('hidden');
if (choice === answer) {
alert("Winner!");
}
if (i < allQuestions.length) {
i += 1;
}
container.empty();
nextQuestion();
});
}
Index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Survey</title>
<link rel="stylesheet" href="assets/bootstrap.min.css">
<link rel="stylesheet" href="assets/bootstrap.responsive.min.css">
<link rel="stylesheet" href="assets/base.css">
</head>
<body>
<!-- index.html -->
<div id="container">
<script src="js/lib/jquery.min.js"></script>
<script src="js/lib/underscore-min.js"></script>
<script src="js/lib/bootstrap.min.js"></script>
<script src="js/app.js"></script>
</div>
<input type='submit' value='Next' id='next'>
</body>
</html>
Remove the following code from withing the function; you're binding the events multiple times. At some time when you click #next once it may advance multiple time as it responds to the multiple binds.
$('input:radio').on('click',function() {
choice = $(this).data("choice");
$('#next').removeClass('hidden');
});
$('#next').on('click',function() {
$('#next').addClass('hidden');
if (choice === answer) {
alert("Winner!");
}
if (i < allQuestions.length) {
i += 1;
}
container.empty();
nextQuestion();
});
Put the code inside a DOM ready event with the modification shown:
$(function() {
$(document).on('change', 'input:radio', function() {
choice = $(this).data("choice");
$('#next').removeClass('hidden');
});
$('#next').on('click',function() {
$('#next').addClass('hidden');
if (choice === answer) {
alert("Winner!");
}
if (i < allQuestions.length) {
i += 1;
}
container.empty();
nextQuestion();
});
});