I am currently making a quiz in Javascript that randomizes questions and answers. I have the questions randomizing but how do I add the answers to go along with a certain question? I also want each answer to be placed in a div of its own, like so: http://imgur.com/a/l9w9j
Here's the code I have so far:
var display = document.getElementById("questions");
var questions = ['What is the weather like?',
'What time of day is it?',
'Whats your favourite music?',
'Which season is your favourite?',
'What colour are your eyes?'];
var questionTracker = [];
var questionAmount = 1;
// Iterate however many times
for (var i = 0; i < questionAmount; i++) {
// Keep creating random numbers until the number is unique
do {
var randomQuestion = Math.floor(Math.random() * questions.length);
} while (existingQuestions());
display.innerHTML += questions[randomQuestion] + '<br>';
// Add the question to the tracker
questionTracker.push(randomQuestion);
}
// If the current random number already exists in the tracker, return true
function existingQuestions() {
for (var i = 0; i < questionTracker.length; i++) {
if (questionTracker[i] === randomQuestion) {
return true;
}
}
return false;
}
And my HTML:
<div id="questions">
</div>
<div id="answers">
<div class="answers-left">
<div class="answer1" tabIndex="1">Sunny</div>
<div class="answer2" tabIndex="2">Raining</div>
</div>
<div class="answers-right">
<div class="answer3" tabIndex="3">Cloudy</div>
<div class="answer4" tabIndex="4">Windy</div>
</div>
<div class="clear"></div>
</div>
Her you can use of object instead of array
var questionData= {
"questions":[
{
"question":"this is hard question to answer",
"answers":[
"yes","no","why not","none"
]
},
{
"question":"this is 2nd hard question to answer",
"answers":[
"yes","no","why not","none"
]
}
]
}
questionData.map(function(question){
//Here you can write the dom structure that you like
})
You can store your questions and answers inside an array of objects
Each object hold a question and an answers property. answers is an array that contains each possible answers.
The following code will take a random question using Math.random() to find a random index. With this index, you can select the object in the array and then select the question and answers.
I added some CSS to add the desired effect. This can be improved with the colors/size/margins/... you want
var questionElement = document.getElementById("questions");
var answersElements = document.getElementsByClassName("answer");
var data = [{
question: 'What is the weather like?',
answers: ['Sunny', 'Raining', 'Cloudy', 'Windy']
}, {
question: 'What time of day is it?',
answers: ['Morning', 'Lunch', 'Evening', 'Night']
}];
var randomIndex = Math.floor(Math.random() * data.length);
questionElement.innerHTML = data[randomIndex].question;
for (let i = 0; i < answersElements.length; i++) {
answersElements[i].innerHTML = data[randomIndex].answers[i];
}
.answer {
display: inline-block;
background-color: #00BCD4;
margin: 1em;
}
<div id="questions">
</div>
<div id="answers">
<div class="answers-left">
<div class="answer" tabIndex="1">Sunny</div>
<div class="answer" tabIndex="2">Raining</div>
</div>
<div class="answers-right">
<div class="answer" tabIndex="3">Cloudy</div>
<div class="answer" tabIndex="4">Windy</div>
</div>
<div class="clear"></div>
</div>
Why not add the answers to the questions in an object array?
var display = document.getElementById("questions");
var answers = document.getElementById("answers");
var answersLeft = document.getElementById("answers-left");
var answersRight = document.getElementById("answers-right");
var questions = [{
"q": "What is the weather like?",
"a": [
"Sunny",
"Raining",
"Cloudy",
"Windy"
]
},
{
"q": "What time of day is it?",
"a": [
"Sunny",
"Raining",
"Cloudy",
"Windy"
]
},
{
"q": "Whats your favourite music?",
"a": [
"Sunny",
"Raining",
"Cloudy",
"Windy"
]
},
{
"q": "Which season is your favourite?",
"a": [
"Sunny",
"Raining",
"Cloudy",
"Windy"
]
},
{
"q": "What colour are your eyes?",
"a": [
"Sunny",
"Raining",
"Cloudy",
"Windy"
]
}
];
var questionTracker = [];
var questionAmount = 1;
// Iterate however many times
for (var i = 0; i < questionAmount; i++) {
// Keep creating random numbers until the number is unique
do {
var randomQuestion = Math.floor(Math.random() * questions.length);
} while (existingQuestions());
display.innerHTML += questions[randomQuestion].q + '<br>';
var answersToQ = questions[randomQuestion].a;
for (var j = 0; j < answersToQ.length; j++) {
var answer = "<p>" + answersToQ[j] + "</p>";
if (j % 2 === 0) {
answersLeft.innerHTML += answer;
} else {
answersRight.innerHTML += answer;
}
}
// Add the question to the tracker
questionTracker.push(randomQuestion);
}
// If the current random number already exists in the tracker, return true
function existingQuestions() {
for (var i = 0; i < questionTracker.length; i++) {
if (questionTracker[i] === randomQuestion) {
return true;
}
}
return false;
}
<style type="text/css">
#answers-left {
position: relative;
float: left;
width: 50%;
}
#answers-right {
position: relative;
float: right;
width: 50%;
}
#answers p {
background-color: blue;
width: 50%;
text-align: center;
color: #fff;
cursor: pointer;
}
</style>
<div id="questions">
</div>
<div id="answers">
<div id="answers-left">
</div>
<div id="answers-right">
</div>
</div>
Here is example that i made for you with following code.
Sorry but i did not have time to make ccs rules, but you can see that questions are mixed and answers for them all mixed all so.
http://devel.vis25.com/test.php
I recommend you to use something like this, for my example you will need Jquery and Jquery templates
Here is link to Jquery download jquery tempaltes
Here is example of you'r tempaltes and html.
<html>
<head>
<script src="https://devel.vis25.com//Vendors/JqueryUI/external/jquery/jquery.js"></script>
<script src="http://devel.vis25.com/Vendors/jquery.tmpl.min.js"></script>
</head>
<body onload="RenderQuestions();">
<div id="Questions"></div>
<script id="Question-Tempalte" type="text/x-jQuery-tmpl">
<div class="Question" id=question-"${ID}">
<div class="Question-text">${QuestionText}</div>
<div class="Question-answer-container" id="Question-answer-container-${ID}"></div>
</div>
</script>
<script id="Answer-Tempalte" type="text/x-jQuery-tmpl">
<div class="answer" id="answer-${ID}">
<div class="answer-text" tabIndex="${ID}">${answerText}</div>
</div>
</script>
</body>
</html>
with javascript do something like this.
//Function that is called in body 'onload' event.
function RenderQuestions(){
//Array of you'r questions as json objects
var questions = [
{ ID : '1', QuestionText : 'What is the weather like?' },
{ ID : '2', QuestionText : 'What time of day is it?' },
{ ID : '3', QuestionText : 'Whats your favourite music?' },
{ ID : '4', QuestionText : 'Which season is your favourite?' },
{ ID : '5', QuestionText : 'What colour are your eyes?' },
];
//Call shuffle function for your questions, so they are mixed randomly.
var ShuffledQuestions = shuffle( questions );
//Loop true all of your questions and render them inside of your questions <div>
//Allso call functions 'RenderAnswers()' by question id value[ 'ID' ].
$.each(ShuffledQuestions, function(index, value){
$( '#Question-Tempalte' ).tmpl( value ).appendTo( '#Questions' );
RenderAnswers( value[ 'ID' ] );
});
}
//Shuffle function return randomly mixed array.
function shuffle( array ) {
var currentIndex = array.length, temporaryValue, randomIndex;
while (0 !== currentIndex) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
//RenderAnswers function takes QuestionID as argument so we can render answer elements for right questions, and we have right answers.
function RenderAnswers( QuestionID ){
var Answers = [];
//Check which question are we rendering.
//Answers for question ID 1 ( 'What is the weather like?' ).
if( QuestionID == 1){
Answers = [
{ AnswersID : 1 , answerText : 'Sunny' },
{ AnswersID : 2 , answerText : 'Raining'},
{ AnswersID : 3 , answerText : 'Cloudy'},
{ AnswersID : 4 , answerText : 'Windy'},
];
}
//Answers for question ID 2 ( 'What time of day is it?' ).
if( QuestionID == 2){
Answers = [
{ AnswersID : 1 , answerText : '8:00' },
{ AnswersID : 2 , answerText : '12:00'},
{ AnswersID : 3 , answerText : '18:00'},
{ AnswersID : 4 , answerText : '00:00'},
];
}
//Answers for question ID 3 ( 'Whats your favourite music?' ).
if( QuestionID == 3){
Answers = [
{ AnswersID : 1 , answerText : 'Rock' },
{ AnswersID : 2 , answerText : 'pop'},
{ AnswersID : 3 , answerText : 'rap'},
{ AnswersID : 4 , answerText : 'EDM'},
];
}
//Answers for question ID 4 ( 'Which season is your favourite?' ).
if( QuestionID == 4){
Answers = [
{ AnswersID : 1 , answerText : 'Summer' },
{ AnswersID : 2 , answerText : 'Winter'},
{ AnswersID : 3 , answerText : ''},
{ AnswersID : 4 , answerText : ''},
];
}
//Answers for question ID 5 ( 'What colour are your eyes?' ).
if( QuestionID == 4){
Answers = [
{ AnswersID : 1 , answerText : 'blue' },
{ AnswersID : 2 , answerText : 'brown'},
{ AnswersID : 3 , answerText : 'green'},
{ AnswersID : 4 , answerText : ''},
];
}
//Shuffle answers.
var ShuffledAnswers = shuffle( Answers );
//Renders answer elements for question.
$( '#Answer-Tempalte' ).tmpl( ShuffledAnswers ).appendTo( '#Question-answer-container-'+QuestionID );
}
Hope i was able to help you, and feel free to ask anything is i did not understand your question right !
Best regards,
Vis25
Related
I am trying to create some questions where you can choose an option from 1 to 5.
I am doing this using radio buttons, and I also change their ID so that they are not the same entity.
Although I am first creating the first question and after the other one, for some reason all the radio buttons are connected and I can only choose 1 button out of the 10 if I create 2 questions, and not 1 from the first question and 1 from the next one.
Does anyone know how to fix this problem? Check my code below to see the problem. Thanks
This is my code:
const questionnaire = document.getElementById('questionaire');
var numsQN = 0;
questionnaire.onclick = ev => {
if (ev.target.tagName === "BUTTON") {
switch (ev.target.className) {
case "remove-qu":
switch (ev.target.parentNode.className) {
case "numQuestion":
numsQN--;
document.getElementById('numberOfNumQuestions').innerHTML = "Number Questions = " + numsQN;
break;
}
ev.target.parentNode.remove();
break;
case "add-numli":
newNumSubquestion(ev.target.closest(".starQuestion").querySelector('ul'), false)
break;
}
}
else {
switch (ev.target.className) {
case "remove-numli":
ev.target.parentNode.remove();
break;
}
}
}
function newNumQuestion() {
questionnaire.insertAdjacentHTML('beforeend', `
<div class='numQuestion'> <div class="numbers"> <ul></ul> </div>`);
}
function newNumSubquestion(q, subquestionNumber) {
q.insertAdjacentHTML('beforeend', `
<li class="numSubquestion">
<span class="numSubquestionName">Sub-question</span>
<div id='colourRadioButtons'> </div>`);
var element = document.getElementById("colourRadioButtons");
var newName = "colourRadioButtons" + subquestionNumber + "";
element.id = newName;
let lastRadio = false;
const numbers = { "5": false, "4": false, "3": false, "2": false, "1": false, },
radioStatic = {
name: "colour", onchange: (event) => {
if (lastRadio) {
numbers[lastRadio] = false;
}
lastRadio = event.currentTarget.value;
numbers[lastRadio] = event.currentTarget.checked;
}, type: "radio"
}; // radioStatic
for (let key in numbers) {
element.appendChild(
Object.assign(document.createElement("label"), { textContent: key })).appendChild(
Object.assign(document.createElement("input"), radioStatic, { checked: numbers[key], value: key }));
if (numbers[key]) {
lastRadio = key;
}
}
}
function generateNumberQuestion() {
let howManyOptionEachNumsQuestionHas = 2;
for (let i = 0; i < 1; i++) {
newNumQuestion(true);
for (let j = 0; j < howManyOptionEachNumsQuestionHas; j++) {
newNumSubquestion(questionnaire.querySelector("div.numQuestion:last-child ul"), j);
}
}
}
document.getElementById("addNumButton").onclick = function () { generateNumberQuestion(); };
<h1 id="myText" contenteditable="true">Survey Name</h1>
<button type="button" id="addNumButton">Number Rating</button>
<form>
<div id="questionaire"></div>
</form>
I want to write a script for a quiz, where there are 4 answers from which only one is correct. I want to make the correct answer appear at random position in one of the 4 buttons, while the rest will be wrong answers. Here's what I've got:
const questions = [
{name: "question1"},
{name: "question2"},
{name: "question3"}
];
function shuffle(questions) {
let currentIndex = questions.length,
randomIndex;
while (currentIndex != 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
[questions[currentIndex], questions[randomIndex]] = [
questions[randomIndex], questions[currentIndex]
];
}
return questions;
}
function start() {
document.getElementById("start").style.display = "none";
shuffle(questions);
document.getElementById("question").innerHTML = questions[0].name;
document.getElementById("correctanswer").style.display = "block";
document.getElementById("wronganswer1").style.display = "block";
document.getElementById("wronganswer2").style.display = "block";
document.getElementById("wronganswer3").style.display = "block";
}
function shownextquestion() {
shuffle(questions);
document.getElementById("question").innerHTML = questions[0].name;
}
function correct() {
document.getElementById("answerstatus") = "Correct Answer!";
}
function incorrect() {
document.getElementById("answerstatus") = "Wrong Answer";
}
<button id="start" onclick="start()">start test</button>
<div id="question"></div>
</br>
<button style="display:none;" id="correctanswer" onclick="shownextquestion();correct()">Correct Answer</button>
</br>
<button style="display:none;" id="wronganswer1" onclick="shownextquestion();incorrect()">Wrong Answer</button>
</br>
<button style="display:none;" id="wronganswer2" onclick="shownextquestion();incorrect()">Wrong Answer</button>
</br>
<button style="display:none;" id="wronganswer3" onclick="shownextquestion();incorrect()">Wrong Answer</button>
</br>
<div id="answerstatus"></div>
Basically, I want the "correctanswer" button to appear randomly in one of the four spaces, while the other three are "wronganswer" 1,2 and 3.
I'm not sure I get the problem correctly. You say you want to shuffle the answers but in your code you try to shuffle the questions.
Assuming you really want to shuffle the answers to a question, I would recommend to choose a different approach:
Define an array of Question objects providing an array with possible answers to the question
Write a function which creates the answer buttons dynamically
Use a shuffle function to shuffle the answers before rendering
/** All questions with possible answers. */
const questions = [
{
name: 'question1',
text: 'Question 1?',
answers: [
{ text: 'Some wrong answer', correct: false },
{ text: 'Another wrong answer', correct: false },
{ text: 'One more wrong answer', correct: false },
{ text: 'The correct answer', correct: true }
]
},
{
name: 'question2',
text: 'Question 2?',
answers: [
{ text: 'Some wrong answer', correct: false },
{ text: 'Another wrong answer', correct: false },
{ text: 'One more wrong answer', correct: false },
{ text: 'The correct answer', correct: true }
]
},
{
name: 'question3',
text: 'Question 3?',
answers: [
{ text: 'Some wrong answer', correct: false },
{ text: 'Another wrong answer', correct: false },
{ text: 'One more wrong answer', correct: false },
{ text: 'The correct answer', correct: true }
]
}
];
/** The index of the question currently being displayed */
let questionIndex = 0;
/** Fisher-Yates shuffle function for shuffling arbitrary arrays */
function shuffle(array) {
const result = [...array];
for (let i = result.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
let temp = result[i];
result[i] = result[j];
result[j] = temp;
}
return result;
}
/**
* Checks for a given question whether the given answer is correct,
* displays an appropriate message, and shows the button for jumping
* to the next question.
*/
function checkAnswer(question, answer) {
document.getElementById('answerstatus').style.display = "block";
const elAnswerStatusText = document.getElementById('answerstatus-text');
if (answer.correct) {
elAnswerStatusText.innerHTML = 'Correct answer!';
}
else {
elAnswerStatusText.innerHTML = 'Wrong answer!';
}
}
/**
* Creates a DOM representation for a question and its answers.
* This function first shuffles the possible answers and creates
* a button element for each, adding an event handler that calls
* function `checkAnswer()`.
*/
function createQuestion(question) {
const elQuestion = document.getElementById("question");
elQuestion.innerHTML = "";
const elQuestionText = elQuestion.appendChild(document.createElement("div"));
elQuestionText.innerHTML = question.text;
for (const answer of shuffle(question.answers)) {
const elButton = elQuestion.appendChild(document.createElement("button"));
elButton.innerHTML = answer.text;
elButton.addEventListener('click', () => checkAnswer(question, answer));
}
}
function showNextQuestion() {
questionIndex = (questionIndex + 1) % questions.length;
document.getElementById('answerstatus').style.display = 'none';
createQuestion(questions[questionIndex]);
}
function start() {
document.getElementById("start").style.display = 'none';
document.getElementById("question").style.display = 'block';
createQuestion(questions[0]);
}
button {
display: block;
width: 200px;
margin-top: 10px;
}
<html>
<head>
</head>
<body>
<button id="start" onclick="start()">start test</button>
<div id="question" style="display: none">
<div id="question-text">
</div>
</div>
<br>
<div id="answerstatus" style="display: none">
<div id="answerstatus-text">
</div>
<br>
<button onclick="showNextQuestion()">Next Question</button>
</div>
</body>
</html>
To also shuffle the buttons you can use your shuffle() function. For that you need to push the buttons to an array:
const buttons = document.querySelectorAll('button.answer');
let button_array = [];
for (let i = 0; i < buttons.length; i++) {
button_array[i] = buttons[i];
}
After shuffling you remove the buttons and append them in the new order. To get this done you could wrap the answer buttons in a container:
<div id="answers">
<button class="answer" id="correctanswer" onclick="shownextquestion();correct()">Correct Answer</button>
...
</div>
That container can simply be emptied with innerHTML = '' and you can easily append the new ordered buttons to it:
shuffle(button_array);
document.getElementById("answers").innerHTML = '';
for (let i = 0; i < button_array.length; i++) {
document.getElementById("answers").append(button_array[i]);
}
The container has also the advantage that you can hide and show all answer buttons at once instead of doing that for every single answer button:
function start() {
document.getElementById("start").style.display = "none";
document.getElementById("answers").style.display = "block";
...
Furthermore are you doing the same thing in start() and shownextquestion() twice, regarding shuffling and inserting the questions. Therefor it's better to put that code in shownextquestion() and call that function in start(). Especially because the code gets bigger when you add the shuffling and inserting for the buttons.
Working example: (i exchanged the inline-styles and the br-tags with CSS-styles and toggled in JavaScript a class instead of manipulating the style-attribute)
const questions = [
{name: "question1"},
{name: "question2"},
{name: "question3"}
];
const buttons = document.querySelectorAll('button.answer');
let button_array = [];
for (let i = 0; i < buttons.length; i++) {
button_array[i] = buttons[i];
}
function shuffle(elements) {
let currentIndex = elements.length,
randomIndex;
while (currentIndex != 0) {
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--;
[elements[currentIndex], elements[randomIndex]] = [
elements[randomIndex], elements[currentIndex]
];
}
return elements;
}
function start() {
document.getElementById("start").classList.add("hide");
document.getElementById("answers").classList.remove("hide");
shownextquestion();
}
function shownextquestion() {
shuffle(questions);
document.getElementById("question").innerHTML = questions[0].name;
shuffle(button_array);
document.getElementById("answers").innerHTML = '';
for (let i = 0; i < button_array.length; i++) {
document.getElementById("answers").append(button_array[i]);
}
}
function correct() {
document.getElementById("answerstatus").innerHTML = "Correct Answer!";
}
function incorrect() {
document.getElementById("answerstatus").innerHTML = "Wrong Answer";
}
* {
margin-bottom: 1rem;
}
button {
display: block;
}
.hide {
display: none;
}
<button id="start" onclick="start()">start test</button>
<div id="question"></div>
<div id="answers" class="hide">
<button class="answer" id="correctanswer" onclick="shownextquestion(); correct()">Correct Answer</button>
<button class="answer" id="wronganswer1" onclick="shownextquestion(); incorrect()">Wrong Answer</button>
<button class="answer" id="wronganswer2" onclick="shownextquestion(); incorrect()">Wrong Answer</button>
<button class="answer" id="wronganswer3" onclick="shownextquestion(); incorrect()">Wrong Answer</button>
</div>
<div id="answerstatus"></div>
I want the answers to appear messy along with the question, so the answers don't always look the same, but the answers seem messy with the question.
example in question 1 Who is really a chef? respond, 'Monica', 'Chandler', 'Rachel', 'Ross' I want those responses to be displayed randomly as' Chandler', 'Ross'' Rachel ',' Monica 'or' Monica ',' Rachel ',' Ross', 'Chandler'
$(document).ready(function() {
$("#remaining-time").hide();
$("#start").on("click", trivia.startGame);
$(document).on("click", ".option", trivia.guessChecker);
});
var trivia = {
correct: 0,
incorrect: 0,
unanswered: 0,
currentSet: 0,
// "seen" property will keep track of the seen questions so we don't re-display them again
seen: [],
// Update: limit the number of question per game. Usong a property so you can change its value whenever you want to change the limit
limit: 4,
timer: 20,
timerOn: false,
timerId: "",
// questions options and answers data
questions: {
q1: "Who is actually a chef?",
q2: "What does Joey love to eat?",
q3: "How many times has Ross been divorced?",
q4: "How many types of towels does Monica have?",
q5: "Who stole Monica's thunder after she got engaged?",
q6: "Who hates Thanksgiving?",
q7: "Who thinks they're always the last to find out everything?"
},
options: {
q1: ["Monica", "Chandler", "Rachel", "Ross"],
q2: ["Fish", "Apples", "Oranges", "Sandwhiches"],
q3: ["5", "2", "1", "3"],
q4: ["3", "8", "11", "6"],
q5: ["Rachel", "Phoebe", "Emily", "Carol"],
q6: ["Joey", "Chandler", "Rachel", "Ross"],
q7: ["Ross", "Phoebe", "Monica", "Chandler"]
},
answers: {
q1: "Monica",
q2: "Sandwhiches",
q3: "3",
q4: "11",
q5: "Rachel",
q6: "Chandler",
q7: "Phoebe"
},
// random number generator
random: (min, max) => Math.floor(Math.random() * (max - min + 1)) + min,
startGame: function() {
trivia.currentSet = 0;
// set "seen" to an empty array for a new game
trivia.seen = [];
trivia.correct = 0;
trivia.incorrect = 0;
trivia.unanswered = 0;
clearInterval(trivia.timerId);
$("#game").show();
$("#results").html("");
$("#timer").text(trivia.timer);
$("#start").hide();
$("#remaining-time").show();
trivia.nextQuestion();
},
nextQuestion: function() {
trivia.timer = 10;
$("#timer").removeClass("last-seconds");
$("#timer").text(trivia.timer);
if (!trivia.timerOn) {
trivia.timerId = setInterval(trivia.timerRunning, 1000);
}
// get all the questions
const qts = Object.values(trivia.questions);
// init the random number
let rq = null;
// firstly, if no more questions to show set rq to -1 to let us know later that the game has finished
// Update: checking if we reached the "limit"
if (trivia.seen.length >= trivia.limit) rq = -1
else {
// otherwise generate a random number from 0 inclusive to the length of the questions - 1 (as array indexing starts from 0 in JS) also inclusive
do {
// generate a random number using the newly added "random" method
rq = trivia.random(0, qts.length - 1);
} while (trivia.seen.indexOf(rq) != -1); // if the question is already seen then genrate another number, do that till we get a non-seen question index
// add that randomly generated index to the seen array so we know that we have already seen it
trivia.seen.push(rq);
// increment the counter
trivia.counter++;
}
// current question index is the generated random number "rq"
trivia.currentSet = rq;
var questionContent = Object.values(trivia.questions)[rq];
$("#question").text(questionContent);
var questionOptions = Object.values(trivia.options)[trivia.currentSet];
$.each(questionOptions, function(index, key) {
$("#options").append(
$('<button class="option btn btn-info btn-lg">' + key + "</button>")
);
});
},
timerRunning: function() {
if (
trivia.timer > -1 &&
// all the questions have already been seen
// Update: now we check against the limit property
trivia.seen.length < trivia.limit
) {
$("#timer").text(trivia.timer);
trivia.timer--;
if (trivia.timer === 4) {
$("#timer").addClass("last-seconds");
}
} else if (trivia.timer === -1) {
trivia.unanswered++;
trivia.result = false;
clearInterval(trivia.timerId);
resultId = setTimeout(trivia.guessResult, 1000);
$("#results").html(
"<h3>Out of time! The answer was " +
Object.values(trivia.answers)[trivia.currentSet] +
"</h3>"
);
}
// if the game ended as we know that -1 means no more questions to display
else if (trivia.currentSet === -1) {
$("#results").html(
"<h3>Thank you for playing!</h3>" +
"<p>Correct: " +
trivia.correct +
"</p>" +
"<p>Incorrect: " +
trivia.incorrect +
"</p>" +
"<p>Unaswered: " +
trivia.unanswered +
"</p>" +
"<p>Please play again!</p>"
);
$("#game").hide();
$("#start").show();
}
},
guessChecker: function() {
var resultId;
var currentAnswer = Object.values(trivia.answers)[trivia.currentSet];
if ($(this).text() === currentAnswer) {
//turn button green for correct
$(this).addClass("btn-success").removeClass("btn-info");
trivia.correct++;
clearInterval(trivia.timerId);
resultId = setTimeout(trivia.guessResult, 1000);
$("#results").html("<h3>Correct Answer!</h3>");
} else {
$(this).addClass("btn-danger").removeClass("btn-info");
trivia.incorrect++;
clearInterval(trivia.timerId);
resultId = setTimeout(trivia.guessResult, 1000);
$("#results").html(
"<h3>Better luck next time! " + currentAnswer + "</h3>"
);
}
},
guessResult: function() {
// no need to increment trivia.currentSet anymore
$(".option").remove();
$("#results h3").remove();
trivia.nextQuestion();
}
};
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="header text-center clearfix">
<h1 class="text-muted">Friends trivia game</h1>
</div>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<div id="game">
<h2>FRIENDS Trivia Game</h2>
<p id="remaining-time" class="lead">Remaining Time: <span id="timer"></span></p>
<p id="question" class="lead"></p>
</div>
<div id="results">
</div>
</div>
<div class="row">
<div id="choices" class="text-center">
<button id="start" class="btn btn-info btn-lg">Start Game</button>
<div id="options">
</div>
</div>
</div>
</div>
<!-- /container -->
Where you begin adding answers to the page, try this code instead:
$.each(Object.values(trivia.options)[trivia.currentSet].sort( () => {
return .5 - Math.random();
}), key => {
$("#options").append(
$('<button class="option btn btn-info btn-lg">' + key + "</button>")
);
});
This is not a secure or efficient way of randomizing an array, but it does the trick for something like this. It just picks a random number between 0 and 1 and subtracts it from 0.5, so the returned number is between -0.5 and 0.5. The sort function does the rest.
This whole thing belongs at the end of your trivia.nextQuestion function.
This whole thing could be done without jQuery. If you're not using it for any particular reason, it might be worth your while to try this in vanilla JavaScript. To get you started, here's the same chunk of code:
const options = document.getElementById("options");
Object.values(trivia.options)[trivia.currentSet].sort( () => {
return .5 - Math.random();
}).forEach(key => {
options.innerHTML += `<button class="option btn btn-info btn-lg">${key}</button>';
});
And while you're at it, look at whether trivia.questions, trivia.options, or trivia.answers need to be objects, or if arrays would work fine. But that belongs mroe on Code Review...
DEMO
In my project, I used a custom Listbox. It's working correctly at one side. If I remove from Left Sidebox, I need to Place that Old Position at the Right side.
$('#items li').click(function() {
var selected = [];
selected.push($(this).html());
$(this).remove();
generateOptionElements(selected, '#selected');
});
populateItems('#items li');
//populate items box with arr
function populateItems(arr, targetMultiSelect) {
arr.sort();
generateOptionElements(arr, targetMultiSelect);
}
//create option elements
function generateOptionElements(arr, targetMultiSelect) {
for (var i = 0; i < arr.length; i++) {
var option = document.createElement('li');
option.insertAdjacentHTML("beforeend",arr[i]);
$(targetMultiSelect).append(option);
}
}
The main pont of the snippet below is that you should create an Array of Objects and manipulate that in JS, and only output the resulting HTML. It's better than manipulating the DOM.
// Array of Objects - the questions and answers and other
// needed information
const questions = [{
position: 0,
side: 1,
q: "0Animals giving birth to young ones:",
a: ["Oviparous", "Oviviviparous", "Viviparous", "Both a and b"]
},
{
position: 1,
side: 1,
q: "1Animals giving birth to young ones:",
a: ["Oviparous", "Oviviviparous", "Viviparous", "Both a and b"]
},
{
position: 2,
side: 1,
q: "2Animals giving birth to young ones:",
a: ["Oviparous", "Oviviviparous", "Viviparous", "Both a and b"]
},
{
position: 3,
side: 1,
q: "3Animals giving birth to young ones:",
a: ["Oviparous", "Oviviviparous", "Viviparous", "Both a and b"]
},
{
position: 4,
side: 1,
q: "4Animals giving birth to young ones:",
a: ["Oviparous", "Oviviviparous", "Viviparous", "Both a and b"]
},
]
// adding the created HTML to the DOM
const populateSides = questions => {
// filling out left and right sides
document.getElementById('right').innerHTML = questionListHtml(questions.filter(e => e.side === 1))
document.getElementById('left').innerHTML = questionListHtml(questions.filter(e => e.side === -1))
// adding click event listener to each question
document.querySelectorAll('.question').forEach(e => {
e.addEventListener('click', function(ev) {
questions.find(el => el.position === Number(e.getAttribute('data-order'))).side *= -1
populateSides(questions)
})
})
}
// template for the list
const questionListHtml = questions => {
let html = ''
html += '<ol>'
questions.forEach(e => {
html += `<li class="question" data-order="${e.position}">${singleQuestion(e)}</li>`
})
html += '</ol>'
return html
}
// template for the single question
const singleQuestion = q => {
let html = ''
html += `${q.q}`
html += `<ol>`
q.a.forEach(e => {
html += `<li>${e}</li>`
})
html += `</ol>`
return html
}
populateSides(questions)
#left {
background: red;
}
#right {
background: yellow
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootswatch/4.3.1/cerulean/bootstrap.min.css" rel="stylesheet" />
<div class="container">
<div class="row">
<div id="left" class="col left">
</div>
<div id="right" class="col">
</div>
</div>
</div>
I'm working on a quiz app, but I can't seem to get the value or the index of the radio buttons on the page.
Here's my code:
HTML:
<div id="container">
<div id="quiz"></div>
<div id="choices"></div>
<input id="next" type="button" value="Next">
<input id="back" type="button" value ="Back">
<div id="results"></div>
</div>
JavaScript:
var allQuestions = [
{
question: "Who is the best in the world?",
choices: ["CM Punk", "John Cena", "Daniel Bryan", "Roman Reigns"],
correctAnswer: 0
},
{
question: "Who is the current WWE World Champion?",
choices: ["John Cena", "Brock Lesnar", "Triple H"],
correctAnswer: 1
},
{
question: "Where is Toronto located?",
choices: ["Ontario", "California", "Georgia", "Texas"],
correctAnswer: 0
},
{
question: "What is the largest California city?",
choices: ["Los Angeles", "San Fransico", "San Deigo", "Anahiem"],
correctAnswer: 0
}
];
var quiz = document.getElementById('quiz');
var choicesContainer = document.getElementById('choices');
var nextButton = document.getElementById('next');
var backButton = document.getElementById('back');
var score = 0;
var questionIndex = 0;
// A function to show the question.
function showQuiz() {
var currentQuestion = allQuestions[questionIndex].question;
quiz.textContent = currentQuestion;
choicesContainer.innerHTML = "";
var choicesNum = allQuestions[questionIndex].choices.length;
for (var i = 0; i < choicesNum; i++) {
var choice = allQuestions[questionIndex].choices[i];
choicesHTML = "<input type='radio' name='choice'>" + choice + "</br>";
choicesContainer.innerHTML += choicesHTML;
}
}
function checkScore() {
//var correctAnswers = allQuestions[questionIndex].correctAnswer;
var radios = document.querySelectorAll('[type=radio]');
var userAnswers;
for (var i = 0; i < radios.length; i++) {
if(radios[i].checked) {
userAnswers = radios[i].value;
console.log(userAnswers);
}
}
}
showQuiz();
nextButton.addEventListener('click', function(){
questionIndex++;
showQuiz();
checkScore();
});
backButton.addEventListener('click', function(){
questionIndex--;
showQuiz();
});
First, I thought it was because I was calling the checkAnswers() function before the DOM was ready, but that doesn't seem the be the case so I'm stuck.
Any help, would be awesome and greatly appreciated. Thanks!
You have an error in your logic.
allQuestions[questionIndex] is undefined, when you click "next" after the last question. You need to check, if theres a question left.
and i think your selector for the radio buttons is wrong.
watch this:
javascript check radio buttons automatically
you need something like
radios = document.getElementsByTagName('INPUT');
for (var i = 0; i < radios.length; i++) {
if(radios[i].type == "radio"){
if(radios[i].checked) {
userAnswers = radios[i].value;
}
}
}
or you select only the checked element with
checkedbutton = document.querySelector("input[name='choice']:checked");
and further: you should add the answers as "value" of the button, like
<input type="radio" name="choice" value="Ontario">
this way you can get the value easy with
checkedbutton.value;