How to generate new object while using the same methods - javascript

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>

Related

Draw in two tables vanilla JS

I am working with program that will randomly choose who is making a Christmas gift to whom.
I've created an empty array. When you add a "player" it's pushing the name into two different arrays. Players[] and Players2[].
When you start a draw. The program writes the names of the Players[] on the left hand side and on the right side it writes the drawn names from Players2[].
Every Player from Players2[], after being drawn, is being deleted from the array so in the end we have an empty Players2[] array and full Players[] array.
The problem is: I can't make a working if statement that is checking if the person will not draw himself...
let Players = [];
let Players2 = [];
const addBTN = document.getElementById('addBTN');
const onlyLetters = /^[a-zżźćóęśńłA-ZŻŹĆÓŁĘŚŃŁ ]+$/;
const refreshBTN = document.getElementById('refreshBTN');
const warningBTNyes = document.getElementById('warning-button-yes');
const warningBTNno = document.getElementById('warning-button-no');
const playersList = document.getElementById('playersList');
const playersList2 = document.getElementById('playersList2');
const startBTN = document.getElementById('startBTN');
const drawLotsBTN = document.getElementById('drawLotsBTN');
addBTN.addEventListener('click', function() {
const input = document.getElementById('addPLAYER');
const person = document.getElementById('addPLAYER').value;
if (input.value == "") {
console.log('error_empty_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Wpisz imię osoby!";
} else if (input.value.match(onlyLetters)) {
console.log('good');
Players.push(person);
Players2.push(person);
playersList.innerHTML = playersList.innerHTML + "<br>" + person;
document.getElementById('addPLAYER').value = "";
document.getElementById('errorMSG').style.color = "green";
document.getElementById('errorMSG').innerHTML = "Powodzenie! Dodaj kolejną osobę.";
} else {
console.log('error_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Coś jest nie tak z imieniem. Pamiętaj aby wprowadzać same litery!";
}
});
refreshBTN.addEventListener('click', function() {
document.getElementById('warning').style.display = "block";
});
warningBTNyes.addEventListener('click', function() {
location.reload(true);
document.getElementById('addPLAYER').value = "";
});
warningBTNno.addEventListener('click', function() {
document.getElementById('warning').style.display = "none";
});
startBTN.addEventListener('click', function() {
drawLotsBTN.disabled = false;
const input = document.getElementById('addPLAYER');
const person = document.getElementById('addPLAYER').value;
if (input.value == "") {
} else if (input.value.match(onlyLetters)) {
console.log('good');
Players.push(person);
Players2.push(person);
playersList.innerHTML = playersList.innerHTML + "<br>" + person;
document.getElementById('addPLAYER').value = "";
document.getElementById('errorMSG').style.color = "green";
document.getElementById('errorMSG').innerHTML = "Powodzenie! Zaczynasz losowanie!";
} else {
console.log('error_input');
document.getElementById('errorMSG').style.color = "red";
document.getElementById('errorMSG').innerHTML = "Coś jest nie tak z imieniem. Pamiętaj aby wprowadzać same litery!";
}
document.getElementById('addPLAYER').disabled = true;
});
drawLotsBTN.addEventListener('click', function() {
for (let i = 0; i = Players2.length; i++) {
if (Players2.length > 0) {
randomPerson = Math.floor(Math.random() * Players2.length);
if (randomPerson != Players.indexOf(i)) {
console.log(Players2[randomPerson]);
playersList2.innerHTML = playersList2.innerHTML + "<br>" + Players2[randomPerson];
Players2.splice(randomPerson, 1);
}
} else {
console.log('error_empty_array');
}
}
});
<div id="warning" class="warning">
<div class="warning-flex">
<h1>Wszelkie wpisane imiona zostaną usunięte</h1>
<div class="warning-buttons">
<button id="warning-button-yes" class="warning-button-yes">Tak</button>
<button id="warning-button-no" class="warning-button no">Nie</button>
</div>
</div>
</div>
<div class="lotteryContainer">
<div class="left">
<p>dodaj osobę</p>
<div class="addPerson">
<input required id="addPLAYER" type="text">
<button id="addBTN">+</button>
<p id="errorMSG"></p>
<div class="refresh">
<button id="refreshBTN">Od nowa</button>
<button id="startBTN">Start</button>
</div>
</div>
</div>
<div class="right">
<p>Uczestnicy</p>
<div class="tables">
<div class="tableLeft">
<p id=playersList></p>
</div>
<div class="tableRight">
<p id="playersList2"></p>
</div>
</div>
<button id="drawLotsBTN">Losuj</button>
</div>
</div>
<script src="app.js"></script>
Now if I understand what your program aims to do, there is a simple algorithm for it.
How I understand your goal:
You have a list of persons who are going to give presents to each other. (like in secret Santa). It is random who will give to who, but each person gives and receives one gift.
How to implement it (i'd normaly use maps, but I am guessing you are more comfortable with arrays):
players = ["Adam", "Bret", "Clay", "Donald"];
players.sort(function(a, b){return 0.5 - Math.random()}); // shuffles array
gives_to = [...players]; // copy values of array
gives_to.push(gives_to.shift()); // let the first element be the last
Here the first player (players[0]) will give to gives_to[0] and the second to gives_to[1] etc.
I've created this JS script trying to use Trygve Ruud algorithm but it doesn't work like desired.
drawLotsBTN.addEventListener('click', function(){
if(Players.length > 0) {
console.log(Players)
Players.sort(function(a, b){
return 0.5 - Math.random();
});
for(let i = 0; i < Players.length; i++){
playersList2.innerHTML = playersList2.innerHTML + "<br>" + Players[i];
}
}
else{
console.log('error_empty_array');
}
});

Javascript - Play sound along with random values from an array

I am trying to make a quizz with random questions. I would like each question to be accompanied by a sound clip that plays automatically as soon as the question is shown. I would also like to have a button that makes it possible for the user to replay the sound clip. How can I achieve this, exactly?
I know how to play individual audio clips with audioClips.play();.
But how about playing audio clips from an array, "synchronized" with the questions?
This is what I have so far:
var country = ["Italy", "Spain", "Portugal", "France", "Greece", "Ireland", "Germany"];
var audioClips = ["italy.mp3", "spain.mp3", "portugal.mp3", "france.mp3", "greece.mp3", "ireland.mp3", "germany.mp3"];
var capital = ["rome", "madrid", "lisbon", "paris", "athens", "dublin", "berlin"];
var random001 = Math.floor(Math.random() * country.length);
document.getElementById("country").textContent = country[random001];
function submit001() {
var b = input001.value.toLowerCase();
var text;
if (b === capital[random001]) {
goToNextQuestion();
text = "Correct!";
} else {
text = input001.value.bold() + " is not correct!";
}
document.getElementById("input001").value = "";
document.getElementById("answer001").innerHTML = text;
}
function goToNextQuestion() {
document.getElementById("answer001").innerHTML = "";
random001 = Math.floor(Math.random() * country.length);
document.getElementById("country").innerHTML = country[random001];
document.getElementById("input001").focus();
}
<p id="message001">What is the capital of <text id="country"></text>?</p>
<input type="text" id="input001" autofocus onKeyDown="if(event.keyCode==13) submit001()">
<p id="answer001"></p>
<button onclick="playAudio()" type="button">Replay Audio</button>
With this problem you're thinking in terms of Arrays and you need to think in terms of Objects. Combine the related information into an Object and you can accomplish your goal with clear, easy-to-read code.
To make this work I had to extensively refactor your code. Here's what I came up with.
HTML
<head>
<style>
#startButton {
display: block;
}
#quiz {
display: none;
}
</style>
</head>
<body>
<div id="startButton">
<button type="button" onclick="startQuiz()">Start Quiz</button>
</div>
<div id="quiz">
<p id="message001">What is the capital of <text id="country"></text>?</p>
<input type="text" id="input001" autofocus onKeyDown="if(event.keyCode==13) checkAnswer()" value="">
<p id="answer001"></p>
<button id="replayButton" type="button" onclick="setAudio()">Replay Audio</button>
</div>
</body>
Javascript
<script>
var country = {
"Italy": {
"audio": "italy.mp3",
"capital": "rome"
},
"Spain": {
"audio": "spain.mp3",
"capital": "madrid"
},
"Portugal": {
"audio": "portugal.mp3",
"capital": "lisbon"
},
"France": {
"audio": "france.mp3",
"capital": "paris"
},
"Greece": {
"audio": "greece.mp3",
"capital": "athens"
},
"Ireland": {
"audio": "ireland.mp3",
"capital": "dublin"
},
"Germany": {
"audio": "germany.mp3",
"capital": "berlin"
}
};
var countryArray = Object.keys(country);
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function nextCountryName(){
let randIndex = getRandomInt(1, countryArray.length) - 1;
return countryArray[randIndex];
};
function playAudio(file){
let playFile = new Audio(file);
playFile.play();
}
function newCountry(newCountryName) {
document.getElementById("country").textContent = newCountryName;
document.getElementById("input001").value = "";
}
function isAnswerCorrect(answer, useCountry) {
let answerId = document.getElementById("answer001");
let ans = answer.toLowerCase();
let text;
if(ans == country[useCountry].capital){
answerId.innerHTML = "Correct!";
return true;
} else {
answerId.innerHTML = ans.bold() + " is not correct!";
return false;
}
};
function setAudio(){
let thisCountry = document.getElementById("country").textContent;
let audioFile = country[thisCountry].audio;
let callStr = "playAudio(\'" + audioFile + "\')";
document.getElementById('replayButton').setAttribute('onclick', callStr);
}
function checkAnswer(){
let inputId = document.getElementById('input001');
let answer = inputId.value;
let thisCountry = document.getElementById("country").textContent;
let audioFile = country[thisCountry].audio;
let result = isAnswerCorrect(answer, thisCountry);
if(result) {
let cntryName = nextCountryName();
newCountry(cntryName);
playAudio(country[cntryName].audio);
}
};
function startQuiz(){
let startingCountry = nextCountryName();
newCountry(startingCountry);
document.getElementById('startButton').style.display = "none";
document.getElementById('quiz').style.display = "block";
playAudio(country[startingCountry].audio);
};
</script>
I converted var country, var audioClips, and var capital arrays into a single Object named var country. This way you can use country.capital or country.audio to get the value you're looking for.
According to this answer it is suggested that you set the audio file type new Audio("file_name") before calling the .play() method.
While answer002, answer003, input002, input003, etc is beyond the scope of your question this code could be easily modified accept such parameters to account for a more extensive quiz.
function playAudio() {
// if you know how to play audio then follow these step
//1. get file name from audioClips array at index randome001 like
audioClip = audioClips[random001]
// do whatever you need to do before playing audio like loading audio file or whatever
//2. play audioClip.
}`

How to debug JavaScript object issues?

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");

ReferenceError: answer is not defined at HTMLButtonElement.button.onclick

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.

Populating html with Javascript

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();
});

Categories