"setstate" in vanilla javascript, enforce changes - javascript

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.

Related

Looping through a nested array, inside an object, inside an array, and pushing into HTML li element

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!

Trying to code a check answer for my coding quiz, but it isn't working properly, what am I missing?

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

get object.properties and place it random in dom element.Vanila Js

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!

Accessing objects from within object?

This is probably a very newbish question, but I am learning javascript and working with pouchDB. I have a search function that returns something like:
{"total_rows":1,"rows":[{"id":"mydoc","score":0.7071067811865475,"doc":{"title":"Guess who?","text":"It's-a me, Mario!","_id":"mydoc","_rev":"1-21bd9b0c99791947618e98a23134b312"},"highlighting":{"text":"It's-a me, Mario!"}}]}
I can access the total_rows value easily obviously, but how would I access the value of 'text'?
Simply with x.rows[0].doc.text.
Edit: To help you understand a little better what's happening here, you're accessing "sub children" with the . operator. We're asking for the rows array inside x and then specifying we want the first row (remember that arrays are 0-indexed, meaning the first element in an array is at position 0).
From there, we just access the doc child, and the text attribute it contains.
var obj = {"total_rows":1,"rows":[{"id":"mydoc","score":0.7071067811865475,"doc":{"title":"Guess who?","text":"It's-a me, Mario!","_id":"mydoc","_rev":"1-21bd9b0c99791947618e98a23134b312"},"highlighting":{"text":"It's-a me, Mario!"}}]};
console.log(obj.rows[0].doc.text);
Hi please cchecck this
var abc = {
"total_rows": 1,
"rows": [
{
"id": "mydoc",
"score": 0.7071067811865475,
"doc": {
"title": "Guess who?",
"text": "It's-a me, Mario!",
"_id": "mydoc",
"_rev": "1-21bd9b0c99791947618e98a23134b312"
},
"highlighting": {
"text": "It's-a me, Mario!"
}
}
]
}
console.log(abc.rows[0].doc.text);
console.log(abc.rows[0].highlighting.text);
it is better to identify each row by using 'id' to parse javascript object.
try this (javascript es6)
const obj = {"total_rows":1,"rows":[{"id":"mydoc","score":0.7071067811865475,"doc":{"title":"Guess who?","text":"It's-a me, Mario!","_id":"mydoc","_rev":"1-21bd9b0c99791947618e98a23134b312"},"highlighting":{"text":"It's-a me, Mario!"}}]}
const id = 'mydoc'
const text = obj.rows.find(item => item.id === id).doc.text
console.log(text)
javascript es5 or previous version
var obj = {"total_rows":1,"rows":[{"id":"mydoc","score":0.7071067811865475,"doc":{"title":"Guess who?","text":"It's-a me, Mario!","_id":"mydoc","_rev":"1-21bd9b0c99791947618e98a23134b312"},"highlighting":{"text":"It's-a me, Mario!"}}]};
var id = 'mydoc';
var text = obj.rows.find(function(item) { return item.id === id; }).doc.text;
console.log(text);

storing quiz questions in local storage

So for a school assignment I have to make an interactive quiz with javascript. That I did, the problem is that it is required for me to store all the questions in an external text file on local storage.
My questions are stored in an array of objects, and I add them to radio buttons with a 'for'-loop
I googled it, but I didn't find an answer that made it clear enough for me...
I understand that I can read files out, but I have no idea how I would add the questions to my existing for-loops
I'm still totally new to JS, and have no idea how to implement this
here's a code snippet, where i take the questions out of the array, and add them to the list with radio buttons
var i = 0;
var len = allQuestions.length;
function frageStellen(i){
var anzahlVarianten = allQuestions[i].choices.length;
for(var j = 0; j < anzahlVarianten; j++){
//create radio buttons
var option = document.createElement("li");
var variante = document.createElement("input");
variante.setAttribute('type', 'radio');
variante.setAttribute('name', 'gestellteFrage'+ i);
option.setAttribute('class', '.option');
//fragen-Inhalt
var inhalt = document.createTextNode(allQuestions[i].choices[j]);
myOptions.appendChild(option);
option.appendChild(variante);
option.appendChild(inhalt);
myQuestion.innerHTML = allQuestions[i].question;
}
}
Here is the link to the full code: http://jsfiddle.net/7HaCz/
please help!
Put this part of your code:
var jsonData = [{
question: "What is Javascript?",
choices: ["An ancient language", "A programming language", "A medieval manuscript", "An internet troll"],
correctAnswer: 1
}, {
question: "Where is Venice?",
choices: ["Peru", "Greece", "US", "Italy", "Congo"],
correctAnswer: 3
}, {
question: "What does RGB mean?",
choices: ["Red, Green, Blue", "Real Graphics Body", "SWAG"],
correctAnswer: 0
}, {
question: "How many strings has a guitar?",
choices: [3, 4, 5, 6, 7, 8],
correctAnswer: 3
}];
In a separate file, then follow this stackoverflow to JSON.parse(jsonData) to get the JSON data out of it again.

Categories

Resources