HTML multiple choice quiz - javascript

I am working on an HTML quiz recently, which is a page shown before a company page we use in my department. If the user answers correctly, then he can get the link to the page he needs to work.
However, when he answers wrongly, he gets a message and he can answer again, but the "Wrong Answer" that he got previously is still shown. That is what i don't want to happen.
The code of the quiz.js file is shown below. Also i post the HTML code of the answer section.
$(document).ready(function()
{
$("#results").click(function() {
if (!$("input[#name=q1]:checked").val())
{
alert("You're not done yet!");
}
else
{
var cat1name = "1";
var cat11name = "None";
var cat1 = ($("input[#name=q1]:checked").val() != "b"); // correct answer
var cat11 = (!cat1); var categories = [];
if (cat1) { categories.push(cat1name) };
if (cat11) { categories.push(cat11name) };
var catStr = 'You answered the following questions incorrectly: ' + categories.join(', ') + '';
$("#categorylist").text(catStr);
$("#categorylist").show("slow");
if (cat1) { $("#category1").show("slow"); };
if (cat11) { $("#category11").show("slow"); };
{ $("#closing").show("slow"); };
}
});
});
<div id="results">
Answer
</div>
<div id="category1">
<p>
<strong>Wrong answer!</strong>
</p>
</div>
<div id="category11">
<p>You answered correctly!</p>
<p><a href="somelink</a></p>
</div>
</div>
</body>
</html>

Related

Values from Array Only Change Upon First Run of a Function

I'm a beginner working on a trivia app, and I'm having a heck of a time getting the questions to iterate properly. I've tried things multiple different ways. Here is my current configuration.
The questions are iterated by the pullQuestions() function. This function pulls from an array called question.
The pullQuestions() function is run when the startbutton is clicked and when the submitA button is clicked. These buttons run either startGame() or submitA() respectively.
Please note, I have not yet implemented score tracking so the expectation of the submit button is currently limited to pulling the next question.
Question HTML
<div id="gameArea" class="questionbox" style="display: none;">
<div class="questionarea">
<h2 id="headerQ">Question Number</h2>
<p id="content">Question Text</p>
</div>
<div class="answerarea">
<!-- This can be ignored. This is where my options are but I'm not using them in my code yet -->
</div>
<button id="submitA" class="submitA" onClick="submitA()">Submit</button>
</div>
startGame() JavaScript (This works as expected)
function startGame(){
document.getElementById("startArea").style.display = "none";
document.getElementById("gameArea").style.display = "block";
question.id = 0;
pullQuestions();
console.log("startgame() Executed", question.id);
console.log(question[0], question[1]);
}
Question Array* (Set as a Global Variable)
function select1() {
if (op1.className == "selectionFalse") {
document.getElementById("op1").className = "selectionTrue";
document.getElementById("op2").className = "selectionFalse";
document.getElementById("op3").className = "selectionFalse";
document.getElementById("op4").className = "selectionFalse";
console.log("selected1()", "If Condition", op1.className);
}
else {
document.getElementById("op1").className = "selectionFalse";
}
}
submitA() JavaScript (Does not iterate through the Array but does increase the id attribute)
function submitA() {
question.id++;
console.log("submitA() Run)", "Question ID: ", question.id, headerQ, content);
}
*pullQuestions() JavaScript (This is run when the two above functions are run, but I only see results when it runs as part of the startGame() function.
function pullQuestions() {
if (question.id == 0) {
document.getElementById("headerQ").innerHTML = question[0].headerQ;
document.getElementById("content").innerHTML = question[0].content;
console.log("pullQuestions() Executed");
console.log("Variables: ", "headerQ = ", headerQ, "content = ", content);
}
if (question.id == 1) {
document.getElementById("headerQ").innerHTML = question[1].headerQ;
document.getElementById("content").innerHTML = question[1].content;
console.log("pullQuestions() Executed");
console.log("Variables: ", "headerQ = ", headerQ, "content = ", content);
}
if (question.id == 2) {
document.getElementById("headerQ").innerHTML = question[2].headerQ;
document.getElementById("content").innerHTML = question[2].content;
console.log("pullQuestions() Executed");
console.log("Variables: ", "headerQ = ", headerQ, "content = ", content);
}
}
I feel like I'm missing something small, but being that I'm new it's possible I'm approaching this all wrong. Any advice or direction is appreciated.
It doesn't work for you in the submitA button because you forgot to activate the call to in it pullQuestions
On the other hand, in startGame you did activate pullQuestions after you changed the id, so it works for you
This is what the function should look like
function submitA() {
question.id++;
pullQuestions();
console.log("submitA() Run)", "Question ID: ", question.id, headerQ, content);
}
I was able to get this to work. I added a variable to determine that the selection is "true." I also added a button to move to the next question so that the submit button / function is separate.

Why is if...else statement only compares single word values?

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>

Replace div contents javascript (no jquery)

Every time a selection is made from a dropdown menu, specific data is pulled from facebook and added to different divs. I am trying to update the contents of the div every time a different selection is made, however at the minute, the contents are just appended on after the initial contents.
This is the code that gets data based on a selection and creates the list from the returned data
<script>
city = document.getElementById("citySelection")
city.addEventListener("change", function() {
var selected = this.value;
var eventsList = document.getElementById("events");
if (selected == "None") {
eventsList.style.display = "none";
} else {
eventsList.style.display = "block";
};
if (selected == 'Bristol') {
getBristolEvents();
};
if (selected == 'Leeds') {
getLeedsEvents();
};
if (selected == 'Manchester') {
getManchesterEvents();
};
if (selected == 'Newcastle') {
getNewcastleEvents();
};
});
function createList(response, listId) {
var list = document.createElement('UL')
for (var i = 0; i < 10; i++) {
var events = response.data[i].name
var node = document.createElement('LI');
var textNode = document.createTextNode(events);
node.appendChild(textNode);
list.appendChild(node)
listId.appendChild(list);
}};
</script
This is the div being targeted:
<html>
<div id="events" style="display: none">
<div id="eventsDiv" style="display: block">
<div id="eventsListOne">
<h3 id='headerOne'></h3>
</div>
<div id="eventsListTwo">
<h3 id='headerTwo'></h3>
</div>
<div id="eventsListThree">
<h3 id='headerThree'></h3>
</div>
</div>
</div>
</div>
</html>
I have tried resetting the innerHtml of the div every time the function to get the data from facebook is called:
<script>
function getEventsThree(fbUrl, title) {
var listId = document.getElementById('eventsListThree');
var headerThree = document.getElementById('headerThree');
listId.innerHtml = "";
headerThree.append(title)
FB.api(
fbUrl,
'GET', {
access_token
},
function(response) {
listId.innerHtml = createList(response, listId)
}
)};
</script>
However, that still doesn't reset the contents of the div.
I've looked at other response but they all use jquery which I am not using.
Can anyone advise on the best way to fix this? Thanks.
I think your Hennessy approach is fine. Generate the inner content, then set .innerHTML.
At least one of your problems, maybe the only one, appears to be that you set .innerHTML to the return value of createList, but that function does not return anything.

How to add Voting System in Angularjs with $localstorage

I want to restrict user to vote only one time for a question using
$localstorage.
Here is my code:
HTML:
<ul>
<li ng-repat="question in questions"> {{question.text}}
<button ng-click="upvote(question)">Vote</button>
</li>
JS:
$scope.upvote = function(question){
var votedQuestions = [];
$localStorage.votedQuestions = votedQuestions;
if($localStorage.votedQuestions.indexof(question._id) === -1){
$localStorage.votedQuestions.push(question._id);
console.log("Thanks for Voting");
}
else {
console.log("You already voted to this question");
}
}
}
it is giving me error like $localStorage.votedQuestions.indexof is not a function
and it's not storing multiple questions, it's just updating the question id in localstorage array on other question click
You always set your $localStorage.votedQuestions to an empty array thus user will always have the possibility to vote to all questions.
Just remove this line and it will works fine
//APP
angular.module('myApp')
.run(['$localStorage', function($localStorage) {
$localStorage.votedQuestions = [];
}])
//Controller
$scope.upvote = function(question) {
if ($localStorage.votedQuestions.indexof(question._id) === -1) {
$localStorage.votedQuestions.push(question._id);
console.log("Thanks for Voting");
} else {
console.log("You already voted to this question");
}
}

Hiding text after clicking on something different

My goal here is to have the riddles in my page to be shown one at a time. My instructor has shown us a way using JavaScript variables. in my HTML I have two riddles shown as an example:
<h5>Question 1</h5>
<p onClick="revealAnswer('answer1','When it is turned into the teacher', 0)">When is homework not homework?</p><br/>
<span id="answer1" class="answers"></span><br/>
<hr>
<h5>Question 2</h5>
<p onClick="revealAnswer('answer2','An Umbrella', 1)">What goes up when rain comes down?</p><br/>
<span id="answer2" class="answers"></span><br/>
<hr>
in an external JavaScript, I have this code to expose the answers:
var isVisible = new Array();
isVisible[0] = false;
isVisible[1] = false;
function revealAnswer(answerId, answer, indexNum){
if(isVisible[indexNum]==false){
document.getElementById(answerId).innerHTML = answer;
isVisible[indexNum]=true;
console.log(answerId);
}
else{
document.getElementById(answerId).innerHTML = "";
isVisible[indexNum]=false;
}
My goal is when you click on "question 1", it shows you the answer, but when you click on "question 2" the answer to "question 1" goes away, and shows you the answer to "question 2". I am entirely new to JavaScript, but my best guess is to either add a new function, add an additional "if" or "else" to the existing "revealAnswer" function. What are your best recommendations?
var isVisible = new Array();
isVisible[0] = false;
isVisible[1] = false;
function revealAnswer(answerId, answer, indexNum){
if(isVisible[indexNum]==false){
var spanAnswer = document.querySelectorAll(".answers");
for(i=0;i < spanAnswer.length ; i++){
spanAnswer[i].innerHTML = '';
isVisible[i] = false;
}
document.getElementById(answerId).innerHTML = answer;
isVisible[indexNum]=true;
console.log(answerId);
}
else{
document.getElementById(answerId).innerHTML = "";
isVisible[indexNum]=false;
}
}
<h5>Question 1</h5>
<p onClick="revealAnswer('answer1','When it is turned into the teacher', 0)">When is homework not homework?</p><br/>
<span id="answer1" class="answers"></span><br/>
<hr>
<h5>Question 2</h5>
<p onClick="revealAnswer('answer2','An Umbrella', 1)">What goes up when rain comes down?</p><br/>
<span id="answer2" class="answers"></span><br/>
<hr>
Here you go
document.querySelectorAll will not work in IE
here is the traditional code which will work in IE as well
function revealAnswer(answerId, answer, indexNum){
if(isVisible[indexNum]==false){
var spanAnswer = document.getElementsByTagName("span");
for(i=0;i < spanAnswer.length ; i++){
if(spanAnswer[i].id == "answer"+(i+1)){
spanAnswer[i].innerHTML = '';
}
}
document.getElementById(answerId).innerHTML = answer;
isVisible[indexNum]=true;
console.log(answerId);
}
else{
document.getElementById(answerId).innerHTML = "";
isVisible[indexNum]=false;
}
}
Jquery would make your life much easier. Go take a look at this : http://www.w3schools.com/JQuery/jquery_hide_show.asp
To hide or show elements using Jquery you only have to do is give an id to your HTML elements as follows : <button id="hide">ButtonHide</button>
And then call an event on that button in JQuery :
$(document).ready(function(){
$("#hide").click(function(){
$("#hide").hide();
});
});
The #is a direct reference to the ID in your html making it easy to access it from your jquery.
If you wanted to hide the answer using jquery all you would have to do is :
Give and ID to it:
<p id="Question1Answer">blablabla</p>
<p id="Question2">blablabla</p>
Set an event on question 2
$(document).ready(function(){
$("#Question2").click(function(){
$("#Question1Answer").hide();
});
});
To make it clearer how to inlcude this into your code go check the link I posted at the top of the answer
Go check on the following link how to include Jquery : http://www.w3schools.com/jquery/jquery_get_started.asp
Here's a different approach. It toggles the visibility of the current answer, and then it hides all the other answers.
This simplifies the HTML, because you don't need any IDs. nextElementSibling grabs the answer that goes with the clicked question.
It also simplifies the JavaScript, because you don't need a global array to hold the visibility of each answer.
function revealAnswer(p) {
var ans= p.nextElementSibling,
all= document.querySelectorAll('.answers');
ans.classList.toggle('visible');
for(var i = 0 ; i < all.length ; i++) {
if(all[i] !== ans) all[i].classList.remove('visible');
}
}
.answers {
display: none;
}
.visible {
display: block;
}
<h5>Question 1</h5>
<p onClick="revealAnswer(this)">When is homework not homework?</p>
<p class="answers">When it is turned into the teacher</p>
<hr>
<h5>Question 2</h5>
<p onClick="revealAnswer(this)">What goes up when rain comes down?</p>
<p class="answers">An Umbrella</p>
<hr>
I know two ways to do this. One would be to put invisible radiobuttons on the page and to write the questions in their labels, but that's quite a peculiar hack. Let's do something simpler.
Instead of storing the state of all answers, you could just store which one is visible. Then, when you click on a question, the currently visible answer is hidden and the new answer is shown.
var visibleAnswer = null;
function revealAnswer(answerId, answer){
var answerElement = document.getElementById(answerId);
if(visibleAnswer) {
visibleAnswer.innerHTML = "";
}
if(!visibleAnswer || visibleAnswer.id !== answerElement.id) {
answerElement.innerHTML = answer;
visibleAnswer = answerElement;
} else {
answerElement.innerHTML = "";
visibleAnswer = null;
}
}
<h5>Question 1</h5>
<p onClick="revealAnswer('answer1','When it is turned into the teacher')">When is homework not homework?</p><br/>
<span id="answer1" class="answers"></span><br/>
<hr>
<h5>Question 2</h5>
<p onClick="revealAnswer('answer2','An Umbrella')">What goes up when rain comes down?</p><br/>
<span id="answer2" class="answers"></span><br/>
<hr>

Categories

Resources