I am making a quiz app that will basically fetch the questions and answers from an API and display it to the webpage. It works fine, but the error handling isn't working. I have a if...else statement that will check if a user has selected the right answer, and if they did, play a sound and display "Nice job" to the user. If they did not, then tell the user that they need to try again. The behavior that I'm getting is very weird. Sometimes when I have chose the correct answer, it says it is not correct. It happens when there is spaces within the answer. For single words such as "true", "false" or "Hello" works fine. I logged the answer to the console stored in a variable called answer_container, when I logged it to the console, the answer and my choice are exactly the same. I have tried using === and == operators to see if that would work, but the result is the same. I have posted the full code including my HTML so that you can see what it is happening. Note it took me couple of tries to get the weird behavior to display.
Here is what I have tried:
var showAnswer = document.getElementById('showAnswer');
var button_score = document.getElementById('ShowScore');
var answer_container;
var url = 'https://opentdb.com/api.php?amount=1';
var score = 0;
var html_container = [];
async function fetchData() {
document.getElementById('next').disabled = true;
document.getElementById('msgSuccess').innerHTML = '';
document.getElementById('check').disabled = false;
document.getElementById('showAnswer').disabled = false;
var getData = await fetch(url);
var toJS = await getData.json();
answer_container = toJS.results[0].correct_answer;
var container = [];
for (var i = 0; i < toJS.results[0].incorrect_answers.length; i++) {
container.push(toJS.results[0].incorrect_answers[i]);
}
container.push(toJS.results[0].correct_answer);
container.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
html_container = [];
container.forEach(function(choices) {
html_container.push(`
<option value=${choices}>
${choices}
</option>
`)
});
document.getElementById('choice').innerHTML = html_container.join();
if (toJS.results[0].type === 'boolean') {
document.getElementById('type').innerHTML =
`This question is a ${toJS.results[0].category} question <br>
It is a true/false question<br>
Difficulty level: ${toJS.results[0].difficulty} <br>
Question: ${toJS.results[0].question}<br>
`;
} else {
document.getElementById('type').innerHTML =
`This question is a ${toJS.results[0].category} question <br>
It is a ${toJS.results[0].type} choice question <br>
Difficulty level: ${toJS.results[0].difficulty} <br>
Question: ${toJS.results[0].question}<br>
`;
}
}
fetchData();
showAnswer.addEventListener('click', function() {
document.getElementById('answer_element').innerHTML = "The answer to this question is " + answer_container;
document.getElementById('answer_element').style.display = "block";
setTimeout(function() {
document.getElementById('answer_element').style.display = "none";
}, 3000);
});
function check() {
var select_answer = document.getElementById('choice').value;
var audio = document.getElementById('audio');
if (select_answer == answer_container) {
score++;
document.getElementById('showAnswer').disabled = true;
document.getElementById('msgSuccess').innerHTML = "Nice job, keep going!";
document.getElementById('next').disabled = false;
document.getElementById('check').disabled = true;
audio.play();
console.log(answer_container);
}
if (select_answer != answer_container) {
score--;
document.getElementById('msgSuccess').innerHTML = "Keep trying, you will get it!";
document.getElementById('next').disabled = true;
console.log(answer_container);
}
}
<!DOCTYPE html>
<html>
<head>
<title>
Quiz App
</title>
</head>
<body>
<div id="type">
</div>
<label>
Select Your Answer...
</label>
<select id="choice">
</select>
<button id="showAnswer">
Show Answer
</button>
<p id="answer_element">
</p>
<button onclick="check()" id="check">
Check
</button>
<p id="msgSuccess">
</p>
<button id="next" onclick="fetchData()">
Next Question
</button>
<audio id="audio">
<source src="https://www.theharnishes.com/khanacademy.mp3" type="audio/mp3">
</audio>
</body>
</html>
You're using the expression select_answer == answer_container to determine if the choice is the correct answer.
select_answer comes from the value attribute of the option you've selected. However, when an answer value contains whitespace, HTML interprets only up to the first whitespace as the "value". When answers like North America come up, the option's value attribute is only North.
When generating your options in your HTML, you need to properly encapsulate them in double quotes ", like so:
html_container.push(`
<option value="${choices}">
${choices}
</option>
`)
Tangential, but it would probably be cleaner if you generated your elements with document.createElement() and Node.appendChild(); in this instance the quotes required to properly set the value attribute on each option would have been added for you.
Nice game!
The issue here is the text is getting truncated on whitespace in the HTML, so the value you're comparing it too doesn't match.
You need quotes in the HTML option to preserve white space.
<option value=${choices} <- picks the first word
<option value="${choices}" <- allows the whole string with spaces
var showAnswer = document.getElementById('showAnswer');
var button_score = document.getElementById('ShowScore');
var answer_container;
var url = 'https://opentdb.com/api.php?amount=1';
var score = 0;
var html_container = [];
async function fetchData() {
document.getElementById('next').disabled = true;
document.getElementById('msgSuccess').innerHTML = '';
document.getElementById('check').disabled = false;
document.getElementById('showAnswer').disabled = false;
var getData = await fetch(url);
var toJS = await getData.json();
console.log(toJS)
answer_container = toJS.results[0].correct_answer;
var container = [];
for (var i = 0; i < toJS.results[0].incorrect_answers.length; i++) {
container.push(toJS.results[0].incorrect_answers[i]);
}
container.push(toJS.results[0].correct_answer);
container.sort(func);
function func(a, b) {
return 0.5 - Math.random();
}
html_container = [];
container.forEach(function (choices) {
html_container.push(`
<option value="${choices}">
${choices}
</option>
`)
});
document.getElementById('choice').innerHTML = html_container.join();
if (toJS.results[0].type === 'boolean') {
document.getElementById('type').innerHTML =
`This question is a ${toJS.results[0].category} question <br>
It is a true/false question<br>
Difficulty level: ${toJS.results[0].difficulty} <br>
Question: ${toJS.results[0].question}<br>
`;
}
else {
document.getElementById('type').innerHTML =
`This question is a ${toJS.results[0].category} question <br>
It is a ${toJS.results[0].type} choice question <br>
Difficulty level: ${toJS.results[0].difficulty} <br>
Question: ${toJS.results[0].question}<br>
`;
}
}
fetchData();
showAnswer.addEventListener('click', function () {
document.getElementById('answer_element').innerHTML = "The answer to this question is " + answer_container;
document.getElementById('answer_element').style.display = "block";
setTimeout(function () {
document.getElementById('answer_element').style.display = "none";
}, 3000);
});
function check() {
var select_answer = document.getElementById('choice').value;
var audio = document.getElementById('audio');
console.log(select_answer, answer_container)
if (select_answer == answer_container) {
score++;
document.getElementById('showAnswer').disabled = true;
document.getElementById('msgSuccess').innerHTML = "Nice job, keep going!";
document.getElementById('next').disabled = false;
document.getElementById('check').disabled = true;
audio.play();
console.log(answer_container);
}
if (select_answer != answer_container) {
score--;
document.getElementById('msgSuccess').innerHTML = "Keep trying, you will get it!";
document.getElementById('next').disabled = true;
console.log(answer_container);
}
}
<!DOCTYPE html>
<html>
<head>
<title>
Quiz App
</title>
</head>
<body>
<div id="type">
</div>
<label>
Select Your Answer...
</label>
<select id="choice">
</select>
<button id="showAnswer">
Show Answer
</button>
<p id="answer_element">
</p>
<button onclick="check()" id="check">
Check
</button>
<p id="msgSuccess">
</p>
<button id="next" onclick="fetchData()">
Next Question
</button>
<audio id="audio">
<source src="https://www.theharnishes.com/khanacademy.mp3" type="audio/mp3">
</audio>
</body>
</html>
Related
<script>
var sum = 0;
var pressYet = false;
function changeIt() {
if(pressYet == false){
sum++;
document.getElementById('test').innerHTML = sum;
pressYet = true;
} else {
document.getElementById('test').innerHTML = "You have already pressed the button";
document.getElementById("button").style.visibility = "hidden";
}
}
</script>
<div id="test">
<b> <var> Test </ var> </b>
</div>
<button onclick="changeIt()" id = "button" >Press If you are here</button>
SO I have this sweet epic button on my website, its very cool, but I want to make it better. I was wondering how to make the variable 'sum' not reset every time I refresh my website. I know there's a term for that but for the life of me I cannot figure it out. I want it so every time someone presses the button, 'sum' gets added one to it and that number would be permanent. So over time that number gets very large.
I am very new to HTML so please be kind to me.
You can save the value to localStorage and then retrieve it from localStorage after page load. Then on the basis of the data you can adjust the page. I have slightly modified your code here
var sum = 0;
var pressYet = localStorage.getItem('pressYet');
function changeIt() {
if (pressYet == null) {
sum++;
document.getElementById('test').innerHTML = sum;
pressYet = true;
localStorage.setItem('pressYet', pressYet);
} else {
document.getElementById('test').innerHTML = "You have already pressed the button";
document.getElementById("button").style.visibility = "hidden";
}
}
(function init() {
if (localStorage.getItem('pressYet') != null || localStorage.getItem('pressYet') != "") {
document.getElementById('test').innerHTML = "You have already pressed the button";
document.getElementById("button").style.visibility = "hidden";
}
})();
<div id="test">
<b> <var> Test </ var> </b>
</div>
<button onclick="changeIt()" id="button">Press If you are here</button>
You can check out the demo https://jsfiddle.net/5jyrk6s8/
I'm a complete JS noob who set off on a mission to create a quiz as a first/second-ish project. I suppose there are better ways to do this than the way I'm doing it, but currently I, after a correct submission of the user, want to remove the current iteration from the array which is converted into text through innerHTML, and do the same for the correct answer/explanation. This works well, up until the last bit. After the user completes the last question, it again removes the data from the array, showing "UNDEFINED" in the screen. I figured that, by adding an if statement to see if array.length > 1, I could circumvent this. I tried avoiding this by having a different if statement return true or false and then using && on the function; to no avail. Any and all if statements here give me the errors:
Uncaught ReferenceError: nextQuestion is not defined
at submitAnswer (VM588 script.js:61)
at HTMLButtonElement.onclick (quizpage.html:19)
I've attached the html and JS underneath.
var questionsOverview = ["1 - 1+1 = ?", "2 - What food do dieters tend to avoid?", "3 - Best fast food chain?"];
var answersOverview = ["[A] 1 [B] 3 [C] 2", "[A] Protein [B] Carbs [C] Glucose", "[A] Burger King [B] KFC [C] McDonalds"];
var answersLetter = ["C", "B", "C"];
var score = 0;
var answerUser = "test"
var currentQuestion = questionsOverview[0];
//set buttons as answersLetter
function setRed() {
document.getElementById(answerUser).style.background = "red";
}
function pressedA() {
answerUser = "A";
setRed();
document.getElementById("B").style.background = "";
document.getElementById("C").style.background = "";
};
function pressedB() {
answerUser = "B";
setRed();
document.getElementById("A").style.background = "";
document.getElementById("C").style.background = "";
};
function pressedC() {
answerUser = "C";
setRed();
document.getElementById("A").style.background = "";
document.getElementById("B").style.background = "";
};
//preps the first question/answer
function changeQuestion() {
document.getElementById("question").innerHTML = questionsOverview[0];
document.getElementById("answer").innerHTML = answersOverview[0];
};
//move to the next question
checkForEnd() && function nextQuestion() {
questionsOverview.shift();
answersOverview.shift();
answersLetter.shift();
changeQuestion();
};
// submit user answer
function submitAnswer() {
var audio = document.getElementById("tleeni");
audio.play();
if(answerUser === answersLetter[0]) {
alert("Correct! You're smart!");
nextQuestion();
}
else {
alert("Too bad!");
}
};
function checkForEnd() {
if (answersOverview.length > 1) {
return true;
} else {
return false;
}
};
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="reset.css">
<script src="script.js" type="text/javascript"></script>
</head>
<body onload="changeQuestion()">
<div class="top-header" id="header">
<font color="white">Quiz</font></div>
<div class="main-content" id="main-content">
<h2 id="question">1</h2>
<h3 id="answer">2</h3>
<h4 id="score>">scorefiller</h4>
<div id="buttons">
<button onClick="pressedA()" class="answers" id="A">A</button>
<button onClick="pressedB()" class="answers" id="B">B</button>
<button onClick="pressedC()" class="answers" id="C">C</button>
</div>
<button onClick="submitAnswer()" id="submit">Submit answer!</button>
</div>
<audio id="tleeni" src="submit.mp3"></audio>
</body>
<style>
#import url('https://fonts.googleapis.com/css?family=Open+Sans|Pacifico');
</style>
Given that I'm really new to programming I'd appreciate any and all feedback. Thank you very much in advance!
I think your issue might be here
//move to the next question
checkForEnd() && function nextQuestion() {
questionsOverview.shift();
answersOverview.shift();
answersLetter.shift();
changeQuestion();
};
You're not actually calling the function nextQuestion; you're only making a boolean check that is equivalent to checkForEnd() && true since a function is a truthy value.
The function declaration is also "lost" hence why you're getting that reference error.
true && function burrito() {
return '🌯';
}
burrito();
// VM1158:1 Uncaught ReferenceError: burrito is not defined
checkForEnd() && function nextQuestion() {}
This doesn't run each time you click the button, nor does it run each time nextQuestion() is called. It does it once, whenever the code is first loaded. Even if it did all it would be doing is creating a named function expression, which is not useable outside the function itself, ie you can't call nextQuestion().
What you want is to use checkForEnd() inside the function and return based on that
function nextQuestion() {
if(!checkForEnd()) return;
questionsOverview.shift();
answersOverview.shift();
answersLetter.shift();
changeQuestion();
};
I'm just trying to make a simple mobile-based calculator. So far I've managed to display the digits pressed up to a certain character limit. I'm trying to make it so it clears the digits within the h1 tag that serves as the display.
I've tried using .innerHTML = "", but that isn't working. How should I fix this?
HTML
<body>
<h1 id="display">Calculator</h1>
<div class="buttons container" id="arithmetic">
<button onclick="clear()" onkeypress="clear()">AC</button>
<button><sup>+</sup>⁄<sub>−</sub></button>
<button>%</button>
<button>÷</button>
<button onclick="number(7)" onkeypress="number(7)">7</button>
<button onclick="number(8)" onkeypress="number(8)">8</button>
<button onclick="number(9)" onkeypress="number(9)">9</button>
<button>×</button>
<button onclick="number(4)" onkeypress="number(4)">4</button>
<button onclick="number(5)" onkeypress="number(5)">5</button>
<button onclick="number(6)" onkeypress="number(6)">6</button>
<button>−</button>
<button onclick="number(1)" onkeypress="number(1)">1</button>
<button onclick="number(2)" onkeypress="number(2)">2</button>
<button onclick="number(3)" onkeypress="number(3)">3</button>
<button>+</button>
<button>.</button>
<button id="doubleSpace" onclick="number(0)" onkeypress="number(0)">0</button>
<button>=</button>
</div>
<div class="calcOptions container">
<button>Arithmetic</button>
<button>Algebra</button>
<button>Calculus</button>
<button>Statistics</button>
</div>
</body>
JavaScript
var currentQuery;
var pastQuery;
var queryLength = document.getElementById("display").innerHTML.length;
function number(n) {
if (document.getElementById("display").innerHTML == "Calculator") {
document.getElementById("display").innerHTML = "";
}
if (queryLength >= 15) {
} else {
currentQuery = document.getElementById("display").innerHTML;
currentQuery += n;
document.getElementById("display").innerHTML = currentQuery;
}
}
function clear() {
currentQuery = "";
document.getElementById("display").innerHTML = currentQuery;
}
You can't name a javascript function with clear(), and the value of queryLength should set after the document ready replace your code by:
var currentQuery;
var pastQuery;
var queryLength;
document.addEventListener("DOMContentLoaded", function(event) {
var queryLength = document.getElementById("display").innerHTML.length;
})
function number(n) {
if (document.getElementById("display").innerHTML == "Calculator") {
document.getElementById("display").innerHTML = "";
}
if (queryLength >= 15) {
} else {
currentQuery = document.getElementById("display").innerHTML;
currentQuery += n;
document.getElementById("display").innerHTML = currentQuery;
}
}
function clearValue() {
currentQuery = "";
document.getElementById("display").innerHTML = currentQuery;
}
and the clear button with:
<button onclick="clearValue()" onkeypress="clearValue()">AC</button>
The problem is that the name of your function clear is already used by this native function document.clear(). Here is a deeper look on why this native function is called and not your function: Is “clear” a reserved word in Javascript?.
The solution is to simply rename your clear() function to something else e.g. allcancel()
You can try using .innerText = "".
Im new in programming and im trying to make my first project in js - hangman game (https://en.wikipedia.org/wiki/Hangman_(game))
So basically i got two buttons in my HTML file, lets say its look like this:
<button id="movies">Movies</button>
<button id="animals">Animals</button>
i want this buttons to be responsible for changing categories in my game. In js i got:
var movies = ["Shawshank Redemption","Alice in a Wonderland"];
var animals = ["Blue whale","Raspberry Crazy-Ant"];
var choice = 1;
if (choice === 0){
var pwdDraw = Math.floor(Math.random() * movies.length);
var pwd = movies[pwdDraw];
pwd = pwd.toUpperCase();
document.write(pwd);
}
else if (choice === 1){
var pwdDraw = Math.floor(Math.random() * animals.length);
var pwd = animals[pwdDraw];
pwd = pwd.toUpperCase();
document.write(pwd);
}
and this is the place where im stucked, i dont know how change var choice by clicking button (also i want to reload page after click). Im at the beginning on my way with js, so i want this code to be pure js, not any customized library.
<button onclick="changeCategory(number)">Click me</button>
<script>
function changeCategory() {
//[..]
}
</script>
https://www.w3schools.com/jsref/event_onclick.asp
thanks a lot for feedback, but i still have some troubles of implementing this js changes, When im doing it on new file with only category changer everything is running smooth. But when i try to add this to my existing code its doesnt work at all. Here you got my code:
codepen.io/iSanox/project/editor/DGpRrY/
First of all, don't put those <br> in JS code like that.
If you want to try to get the choice by clicking on the button then here's how you can do it:
HTML
<button id="movies" class="choice" value="0">Movies</button>
<br/>
<button id="animals" class="choice" value="1">Animals</button>
JS
var buttons = document.querySelectorAll(".choice");
function doSomething(e)
{
// You can get choice value by either doing:
var choice = e.target.value;
// OR
var choice = this.value;
// Continue your work here
}
for(var i = 0; i < buttons.length; i++)
{
buttons[i].addEventListener("click", doSomething);
}
Feel free to ask any questions.
Simply you can use onclick event. After some changes your code should look like this.
var movies = ["Shawshank Redemption", "Alice in a Wonderland"];
var animals = ["Blue whale", "Raspberry Crazy-Ant"];
var catname = document.getElementById('cat-name');
function selectCategory(choice) {
var pwd, pwdDraw;
if (choice === 0) {
pwdDraw = Math.floor(Math.random() * movies.length);
pwd = movies[pwdDraw];
} else if (choice === 1) {
pwdDraw = Math.floor(Math.random() * animals.length);
pwd = animals[pwdDraw];
}
pwd = pwd.toUpperCase();
catname.innerText = pwd;
}
<p>Choose Category</p>
<button id="movies" onclick="selectCategory(0)">Movies</button>
<button id="animals" onclick="selectCategory(1)">Animals</button>
<div id="cat-name"></div>
Even better with Object and Arrays
var categories = {
movies: ["Shawshank Redemption", "Alice in a Wonderland"],
animals: ["Blue whale", "Raspberry Crazy-Ant"]
};
var catname = document.getElementById('cat-name');
function selectCategory(choice) {
var pwdDraw = Math.floor(Math.random() * categories[choice].length);
var pwd = categories[choice][pwdDraw];
pwd = pwd.toUpperCase();
catname.innerText = pwd;
}
<p>Choose Category</p>
<button id="movies" onclick="selectCategory('movies')">Movies</button>
<button id="animals" onclick="selectCategory('animals')">Animals</button>
<div id="cat-name"></div>
I managed to save the text that is in the input field but the problem is that i do not know how to save the button. The buttons turn white when i click on them and the price of that seat will be visible in the input field. The price saves but the button does not stay white.
<script>
function changeBlue(element) {
var backgroundColor = element.style.background;
if (backgroundColor == "white") {
element.style.background = "blue";
add(-7.5)
} else {
element.style.background = "white";
add(7.5)
}
}
function add(val) {
var counter = document.getElementById('testInput').value;
var b = parseFloat(counter,10) + val;
if (b < 0) {
b = 0;
}
document.getElementById('testInput').value = b;
return b;
}
function save(){
var fieldValue = document.getElementById("testInput").value;
localStorage.setItem("text", fieldValue)
var buttonStorage = document.getElementsByClass("blauw").value;
localStorage.setItem("button", buttonStorage)
}
function load(){
var storedValue = localStorage.getItem("text");
if(storedValue){
document.getElementById("testInput").value = storedValue;
}
var storedButton = localStorage.getItem("button");
if(storedButton){
document.getElementsByClass("blauw").value = storedButton;
}
}
</script>
<body onload="load()">
<input type="text" id="testInput"/>
<input type="button" id="testButton" value="Save" onclick="save()"/>
<input class="blauw" type="button" id="testButton2" value="click me to turn white"
style="background-color:blue" onclick="changeBlue(this)">
<input class="blauw" type="button" id="testButton2" value="click me to turn white"style="background-color:blue" onclick="changeBlue(this)">
</body>
i made a small sample of what i want to do. And i do not want to use the Id's of the buttons because i have like 500 of them in a table.
That's because getElementsByClass (it's getElementsByClassName btw) returns a node list of all the elements with that class.
To make it work, you need to go through all the items in the list, using a for-loop, and set the value of each individual element to the localStorage-value.
See these links for more information:
Link 1
Link 2
Very small mockup to give you an idea:
(In the JS, I put in comments the lines of code you would be using for your situation.)
function changeValues() {
var list = document.getElementsByClassName("child"); //var list = document.getElementsByClassName("blauw");
for (var i=0; i<list.length; i++) {
list[i].innerHTML = "Milk"; //list[i].value = storedButton;
}
}
<ul class="example">
<li class="child">Coffee</li>
<li class="child">Tea</li>
</ul>
<p>Click the button to change the text of the first list item (index 0).</p>
<button onclick="changeValues()">Try it</button>