I'm creating quiz game.
I have separate .js file with array of objects for questions,like this:
var questions = [
{
ask: "question",
choice1: "answer",
choice2: "answer",
choice3: "answer",
correct: "correct answer"
},
];
then i get random object from array:
let random = questions[Math.floor(Math.random() * questions.length)];
then i can send these object.properties to dom like this:
question.innerHTML = random.ask
answer1.innerHTML = random.choice1;
answer2.innerHTML = random.choice2;
answer3.innerHTML = random.choice3;
answer4.innerHTML = random.correct;
And everything works fine but i need to randomize these answers.In ways like this every time the correct answer is on same place but i need answers and correct answer to take random place in dom.
I'm stuck in this problem,trying every solution i can find on google but no success.
You can use the same logic to randomize choices. One of the ways this can be done is as below:
var questions = [
{
ask: "question",
choice1: "answer 1",
choice2: "answer 2",
choice3: "answer 3",
correct: "correct answer"
},
];
let random = questions[Math.floor(Math.random() * questions.length)];
console.log(random);
// Make an array of choices key
let choices = [];
Object.keys(random).forEach((item, index) => {
if(key !== "ask") {
choices.push(random[item]);
}
});
console.log(choices);
function getRandomAnswer() {
// Get a random number
let randomNum = Math.floor(Math.random() * choices.length);
// Store random answer in a variable
let answer = choices[randomNum];
// Remove used up answer from choices array
choices.splice(randomNum, 1);
return answer;
}
console.log("Random Answer: ", getRandomAnswer());
console.log("Random Answer: ", getRandomAnswer());
console.log("Random Answer: ", getRandomAnswer());
console.log("Random Answer: ", getRandomAnswer());
I have made a jsFiddle of this as well. You can optimize this as per your needs.
Hope it helps!
Related
I'm trying to create a timed quiz for a bootcamp challenge I'm taking. I'm stuck on a part where I need to get access of my "questions" array, in which contains 5 "question" objects and an "answers" array inside each object as well as another key named correctAnsw which contains the correct answer to the question, as seen in the code below(i've snipped it down to just one of the questions/answers but there are currently 5.) I'm not sure if this is even the correct way of storing my questions for my quiz but this is what I've done so I'd like to know if this is bad practice or not.
The issue I'm facing right now is I need to dynamically create li objects which contain the "answers" to my question so then I can move on and do things like checking if it's the correct answer etc.
var questions = [
{
question: "What is a string in javascript?",
answers: [
"Something that lets you put words",
"Something that lets numbers",
"A type of function",
"A property of the DOM"
],
correctAnsw: "Something that lets you put words"
}];
function renderQuestions(){
questionTitle.innerHTML = "";
questionChoices.innerHTML = "";
for(var o in questions){
let qst = document.createElement("li");
questionChoices.append(qst);
qst.innerHTML = questions[o]; }
}
Currently this just displays li's with [object Object].
I'm really not sure where to go from here so any help would be appreciated. thanks. also don't pay too much attention to the content of the questions lol I will revist this once I've finished what I need to do
Is this what you want ?
forEach is easiest way to loop throw an nested array.
var questions = [
{
question: "What is a string in javascript?",
answers: [
"Something that lets you put words",
"Something that lets numbers",
"A type of function",
"A property of the DOM"
],
correctAnsw: "Something that lets you put words"
},
{
question: "What is an array of objects in javascript?",
answers: [
"Something that lets you put words",
"Something that lets numbers",
"A type of function",
"A property of the DOM"
],
correctAnsw: "Something that lets you put objects on array"
}
];
function renderQuestions(){
questions.forEach(function (qst) {
let questionTitle = document.createElement("h3");
questionTitle.innerHTML = qst.question;
document.getElementById("questions").appendChild(questionTitle);
qst.answers.forEach(answer => {
// Create an "li" node:
let node = document.createElement("li");
let textnode = document.createTextNode(answer);
node.appendChild(textnode);
document.getElementById("questions").appendChild(node);
//questionChoices.append(qst);
})
});
}
renderQuestions();
<div id='questions' >
</div>
function renderQuestions(){
questionTitle.innerHTML = "";
questionChoices.innerHTML = "";
for(var o in questions){
let qst = document.createElement("li");
qst.innerHTML = questions[o].question;
questionChoices.append(qst);
}
}
questions[o] is an object and not a string.
When an object is converted to string, it becomes [object, object]. So you will have to specify a string property inside it.
If you are trying to create answers inside the qst?
the you would have to loop for the answers array and create the elements.
function renderQuestions(){
questionTitle.innerHTML = "";
questionChoices.innerHTML = "";
for (var o in questions) {
questionTitle.innerHTML = questions[o].question
questions[o].answers.forEach(ans => {
let qst = document.createElement("li");
qst.innerHTML = ans;
questionChoices.append(qst);
})
}
}
But remember, it will change the questionTitle on each iteration and add all the options together.
If this is to display individually, then the code needs to add all elements dynamically as,
var questions = [
{
question: "What is a string in javascript?",
answers: [
"Something that lets you put words",
"Something that lets numbers",
"A type of function",
"A property of the DOM"
],
correctAnsw: "Something that lets you put words"
}
];
function renderQuestions() {
const q = document.getElementById('questions')
for (var o in questions) {
const questionTitle = document.createElement('div');
const questionChoices = document.createElement('ul');
questionTitle.innerHTML = questions[o].question
questions[o].answers.forEach(ans => {
let qst = document.createElement("li");
qst.innerHTML = ans;
questionChoices.appendChild(qst);
})
q.appendChild(questionTitle)
q.appendChild(questionChoices)
}
}
renderQuestions();
<div id="questions"></div>
I agree with the last answer. You probably thought that by typing questions[0] you're accessing the object keys you've created, but thats not the case.
You've created an array of objects, with just one object in this case. So questions[0] is the entire object, you have to loop through it as Mohan showed you.
Let me know if it helped. Happy coding!
I am new to Js, and i am coding a simple quiz app with HTML, CSS and JS to learn.
I am a mobile developer and use Flutter and Dart, dart is pretty similar to JS. On the quiz app, when someone presses the next button after an answered question, i want it to switch to the next question.
When the user presses the button nothing happens... In dart i would use the setState method, which forces the UI to reload with the updated changes. Is there an equivalent method in JS? I found that setState is used in ReactJS, however this is coded in vanilla Js.
I have an Array of 2 questions (which are maps containing the questiopn text, answer alternatives and correct answer). Then I have an integer variable which is the questionIndex. So first question the index i 0, and when the user presses the next button ( to go to the next question) it should increment by 1.
Here is the code for the button click:
function onClickNext() {
console.log("called");
currentQuestionIndex++;
}
the Array of questions:
const questions = [
{
question: "What is the capital of Sweden?",
"alt 1": "Stockholm",
"alt 2": "Gothenburg",
"alt 3": "Malmö",
"alt 4": "Linköping",
correctIndex: 0,
},
{
question: "What is the capital of England?",
"alt 1": "London",
"alt 2": "Manchester",
"alt 3": "Bournemouth",
"alt 4": "Cardiff",
correctIndex: 0,
},
];
And here are the dynamic HTML components (the question + answer alternatives, which are suppoosed to change when next is pressed, so it moves onto the next question.
document.getElementById("question").innerHTML =
questions[currentQuestionIndex]["question"];
button1.innerHTML = questions[currentQuestionIndex]["alt 1"];
button2.innerHTML = questions[currentQuestionIndex]["alt 2"];
button3.innerHTML = questions[currentQuestionIndex]["alt 3"];
button4.innerHTML = questions[currentQuestionIndex]["alt 4"];
Would be really thankful for some guidance, and also if someone knows a way to make my code more consise and efficiant.
Thank you!
Since Vanilla JS has no state listeners that will update the DOM automatically, you can program this yourself, for example:
function onClickNext() {
console.log("called")
currentQuestionIndex++
drawQuestionScreen()
}
function drawQuestionScreen(){
document.getElementById("question").innerHTML =
questions[currentQuestionIndex]["question"];
button1.innerHTML = questions[currentQuestionIndex]["alt 1"];
button2.innerHTML = questions[currentQuestionIndex]["alt 2"];
button3.innerHTML = questions[currentQuestionIndex]["alt 3"];
button4.innerHTML = questions[currentQuestionIndex]["alt 4"];
}
Just populate the question HTML anew after calling onClickNext so that the reassignment has an effect.
To make the code more concise, save the question at the current index in a variable first, instead of accessing through the index each time.
const questionDiv = document.getElementById("question");
const populateQuestion = () => {
const question = questions[currentQuestionIndex];
questionDiv.innerHTML = question.question;
button1.innerHTML = question["alt 1"];
button2.innerHTML = question["alt 2"];
button3.innerHTML = question["alt 3"];
button4.innerHTML = question["alt 4"];
}
// populate on pageload:
populateQuestion();
// and also on click:
function onClickNext() {
currentQuestionIndex++;
populateQuestion();
}
An even better approach would be to use an array for the buttons and answers instead of separate property and variable names. Consider naming the array of possible answers answers instead of alt, it'll probably make more sense at a glance.
const populateQuestion = () => {
const question = questions[currentQuestionIndex];
questionDiv.innerHTML = question.question;
question.answers.forEach((answer, i) => {
buttons[i].textContent = answer;
});
}
You should also consider using .textContent - only use .innerHTML when deliberately inserting HTML markup.
Here's the code I'm trying to get to work:
function checkAnswer(questionIndex) {
// This ID goes to a div storing the four buttons
var answersId = document.getElementById("answers");
//The four spans inside the buttons which has data-answer, targeting at their id. The id and data-answer are the same value.
var answer0 = document.getElementById("option0").getAttribute("data-answer");
var answer1 = document.getElementById("option1").getAttribute("data-answer");
var answer2 = document.getElementById("option2").getAttribute("data-answer");
var answer3 = document.getElementById("option3").getAttribute("data-answer");
answersId.addEventListener("click", function (event) {
if (event.target.hasAttribute("data-answer")) {
event.preventDefault;
if (answer0 == questionList[questionIndex].correctAnswer) {
console.log(answer0)
score++;
console.log(score)
console.log("This is option0")
}
else if (answer1 == questionList[questionIndex].correctAnswer) {
console.log(answer1)
score++;
console.log(score)
console.log("This is option1")
} else if (answer2 == questionList[questionIndex].correctAnswer) {
console.log(answer2)
score++;
console.log(score)
console.log("This is option2")
} else if (answer3 == questionList[questionIndex].correctAnswer) {
console.log(answer3)
score++;
console.log(score)
console.log("This is option3")
} else {
console.log(score)
}
}
});
}
This is sorta hard coded right now, but I want to make sure it actually works before optimizing it.
Basically, I have buttons for a multiple choice quiz, and the idea is that depending on the button clicked, they get a point for choosing the correct answer. In this case, the data-answer should match whatever the correct answer is. (If the correct answer is option1, then "option1" == "option1")
But no matter what button is clicked (in this case, the answer is indeed option1), it gives the point and gives the console.log for option 1, meaning that it constantly chooses that if statement even when I'm picking the other buttons.
It's just driving me crazy that the wrong answer, which is the else statement, isn't being recognized
or rather, it keeps recognizing the second if statement despite clicking the wrong answer. I think my logic is sound, it just isn't working right.
Do you know what I could be missing here?
Edit: Here's the questionList array being referenced, and the objects for each of those variables:
var question1 = {
text: "Commonly used data types do NOT include:",
choices: ["1 - Booleans", "2 - Alerts", "3 - Strings", "4 - Numbers"],
correctAnswer: "option1",
};
var question2 = {
text: "The condition of an if/else statement is enclosed within ______.",
choices: ["1 - Quotes", "2 - Curly Brackets", "3 - Parentheses", "4 - Square Brackets"],
correctAnswer: "option2",
};
var question3 = {
text: "Arrays in Javascript can be used to store ______.",
choices: ["1 - Numbers and strings", "2 - Other Arrays", "3 - Booleans", "4 - All of the above",],
correctAnswer: "option3",
};
var question4 = {
text: "String values must be enclosed within ______ when being assigned to variables.",
choices: ["1 - Quotes", "2 - Curly Brackets", "3 - Commas", "4 - Parentheses"],
correctAnswer: "option0",
};
var question5 = {
text: "A very useful tool used during development and debugging for printing content to the debugger is:",
choices: ["1 - Javascript", "2 - console.log", "3 - Terminal/bash", "4 - For loops"],
correctAnswer: "option1",
};
var questionList = [question1, question2, question3, question4, question5];
Edit 2:
Adding where I'm calling the function. This time I moved the eventlistener out of the checkAnswer() function and right before it is called.
document.getElementById("start-quiz").addEventListener("click", function (event) {
event.preventDefault;
event.stopPropagation;
countDown = 75;
countDownSpan.textContent = countDown;
document.querySelector("#description").style.display = "none";
document.querySelector("#start-quiz").style.display = "none";
contentId.style.textAlign = "left";
setTime();
createAnswers();
generateQA(0);
var answersId = document.getElementById("answers");
answersId.addEventListener("click", function (event) {
checkAnswer(0)
});
});
Edit 3:
If it helps, here is the link to the github page:
https://github.com/WarriorofZarona/Coding-Quiz
GitHub
There is an event handler in the body tag.
<body onload="hangmanGame.populateQuestions();">
It is supposed to get a random position of the array...
const hangmanGame = {
obtainRandom(x) {
return Math.floor(Math.random() * Math.floor(x));
},
populateQuestions() {
let randNum = obtainRandom(5);
let numToPopulate = stemQuestions[randNum];
console.log(randNum);
console.log(numToPopulate);
},
stemQuestions : ['What do roots of a quadratic equation represent in a parabola?',
'What is a chemical process where a solid turns into a gas without going through a liquid stage',
'What is the name of the peculiar kind of inheritance pertinent to JavaScript?',
'What is the product of mass and velocity?',
'What is acceleration with respect to velocity?'],
stemAnswers : ['intercepts','sublimation','prototype','momentum','derivative']
}
But according to the console, both values are undefined...
Can you please give me some insight?
obtainRandom and stemQuestions are properties of hangmanGame, so in order to refer to them from inside populateQuestions you need to use this:
populateQuestions() {
let randNum = this.obtainRandom(5);
let numToPopulate = this.stemQuestions[randNum];
console.log(randNum);
console.log(numToPopulate);
}
All I want to do is have the program select random questions (each question is within a function and fills a blank area in the HTML so all questions appear in the same area) but it does not work. Does anyone have any idea why? I am meant to click correct answer and it executes the correctFunction but nothing happens. Cheers!
var randomFunctions = [
"Question2", "Question3",
"Question4", "Question5",
"Question6", "Question7",
"Question8"
];
var rand = randomFunctions[Math.floor(Math.random() * randomFunctions.length)];
function correctFunction() {
rand();
}
correctFunction()
You must provide actual functions that can be invoked, not strings (which can't). So, your array will wind up holding references to existing functions or the actual functions themselves.
Based on your updated requirement that possible answers should also be shown along with the question, we need to rethink what you are storing in your array. Since a question will have associated possible answers, the best way to store each question with its answers is in an object. So, in the end, we will have an array of objects.
function q1(){ console.log("hello from q1"); }
function q2(){ console.log("hello from q2"); }
function q3(){ console.log("hello from q3"); }
function q4(){ console.log("hello from q4"); }
var randomFunctions = [q1, q2, q3, q4, function(){
console.log("hello from inline anonymous function.");
}];
var rand = randomFunctions[Math.floor(Math.random() * randomFunctions.length)];
rand();
Now, based on your use case, you really don't need or want to store an array of functions, you need to store an array of questions and then have one function that processes that randomly selected question. Like this:
// Get reference to HTML output area
var question = document.getElementById("questionArea");
var answer = document.getElementById("answerArea");
var btn = document.getElementById("btnGetQuestion");
// Set up button click event:
btn.addEventListener("click", showQuestion);
// Set up questions/answers array as an array of objects so that
// the questions and answers can be connected:
var qa = [
{
question:"What is your name?",
answers: ["Bob","Sally", "Mary", "Tim"]
},
{
question:"What is your favorite color?",
answers: ["Red","Green", "Blue", "Orange"]
},
{
question:"What is the average air speed of a laden swallow?",
answers: ["22 mph","18 mph", "17 kmh", "African or European?"]
}
];
// One function to process question:
function showQuestion(){
// Get a random number based on lenght of the questions array
var num = Math.floor(Math.random() * qa.length);
// Get a random object out of the array and extract the question from the object
question.textContent = qa[num].question;
// Loop over all the values in the "answers" object array
// and display them. Build up an output string as well
var html = "<form>";
qa[num].answers.forEach(function(answer, index){
html += "<input type='radio' name='q" + index + "' value='" + answer + "'>" + answer;
});
// close the string and display:
html += "</form>";
answer.innerHTML = html;
}
button {
margin:2em 0;
}
#answerArea {
margin: 1em 0 0 1em;
}
<div id="questionArea"></div>
<div id="answerArea"></div>
<button id="btnGetQuestion">Get A Question</button>