I'm building a simple trivia app and so far its great, but I have a problem with proceeding to the next question.
oddly enough when the user Answer correctly to the question and presses the submit button it does increment to the next question but if they answer correctly again it does nothing.
Here is my code:
<div class="app">
<h2 id="question"></h2>
<button class="options" type="button" value="val"></button>
<button class="options" type="button" value="val"></button>
<button class="options" type="button" value="val"></button>
<button class="options" type="button" value="val"></button>
</br>
<button id="submit" type="button" name="button">Submit</button>
<button id="back" type="button" name="button">Back</button>
</div>
var data = {
currentQuestion: 0,
questions:[
{
answers:[1,3,5,6],
question:'how much is 3+3',
correctAnswer:6
},
{
answers:[1,3,5,2],
question:'how much is 1+1',
currectAnswer:2
},
{
answers:[1,8,5,6],
question:'how much is 4+4',
correctAnswer:8
},
{
answers:[1,8,10,6],
question:'how much is 4+6',
correctAnswer:8
}
]
}
var options = document.querySelectorAll('.options');
var question = document.querySelector('#question');
var backBtn = document.querySelector('#back');
var submitBtn = document.querySelector('#submit');
function init() {
newQuestion();
optionClick();
evaluate();
back();
}
function newQuestion() {
question.textContent = data.questions[data.currentQuestion].question;
for(var i = 0; i< data.questions.length; i++) {
options[i].textContent = data.questions[data.currentQuestion].answers[i]
}
}
function optionClick() {
options.forEach(function(elem) {
elem.addEventListener('click', function() {
this.classList.toggle('picked')
})
})
}
function evaluate() {
submitBtn.addEventListener('click', function() {
for(i = 0; i < options.length; i++) {
if(options[i].classList.contains('picked') && options[i].textContent == data.questions[data.currentQuestion].correctAnswer && data.currentQuestion <= 6){
options[i].classList.remove('picked')
data.currentQuestion++
newQuestion();
}
}
})
}
As has already been answered in the comments, the problem was a typo, currectAnswer rather than correctAnswer. It's kind of moot answering now, but I also wanted to suggest some other improvements.
The first thing I would do is instead of using a group of buttons, use a group of radio buttons. You can style them to look like a button if you want, plus you get free functionality by doing that. Radio buttons enforce only having one answer selected without any need to check for multiple answers in code.
Instead of using named functions that when called attach an anonymous function as an event handler, just create a named function and then attach them directly to the elements.
Pulling it together it would look something like this:
'use strict';
var data = {
currentQuestion: 0,
questions:[
{
answers:[1,3,5,6],
question:'how much is 3+3',
correctAnswer:6
},
{
answers:[1,3,5,2],
question:'how much is 1+1',
correctAnswer:2
},
{
answers:[1,8,5,6],
question:'how much is 4+4',
correctAnswer:8
},
{
answers:[1,8,10,6],
question:'how much is 4+6',
correctAnswer:10
}
]
}
var options = document.querySelectorAll('#options input');
var question = document.querySelector('#question');
var backBtn = document.querySelector('#back');
var submitBtn = document.querySelector('#submit');
function nextQuestion () {
if (data.currentQuestion < data.questions.length - 1) {
data.currentQuestion += 1;
displayQuestion();
} else {
data.currentQuestion = data.questions.length;
submitBtn.removeEventListener('click', evaluate);
backBtn.removeEventListener('click', prevQuestion);
question.textContent = "Done!"
}
}
function prevQuestion () {
if (data.currentQuestion > 0) {
data.currentQuestion -= 1;
displayQuestion();
}
}
function displayQuestion () {
question.textContent = data.questions[data.currentQuestion].question;
options.forEach(function (option, index) {
let answer = data.questions[data.currentQuestion].answers[index];
// set the value of the radio button
option.value = answer;
// set the text of the label next to it
option.nextElementSibling.textContent = answer;
// reset the selected value
option.checked = false
});
}
function evaluate () {
let correctAnswer = data.questions[data.currentQuestion].correctAnswer;
// get the value of the currently selected answer
let selectedAnswer = document.querySelector('#options :checked');
if(selectedAnswer && selectedAnswer.value == correctAnswer){
nextQuestion();
}
}
submitBtn.addEventListener('click', evaluate);
backBtn.addEventListener('click', prevQuestion);
displayQuestion();
fieldset {
border: none;
}
/* highlight the label immediately after the selected radio button */
#options input:checked + label {
border: 3px red solid;
}
/* hide the actual radio button
that the labels are controling. */
#options input {
display: none;
}
/* make the label look like a button */
#options label {
padding: .5em;
background: #eee;
border: outset 1px #eee;
}
<div class="app">
<h2 id="question"></h2>
<fieldset id="options">
<input id="answer1" type="radio" name="answers"> <label for="answer1"></label>
<input id="answer2" type="radio" name="answers"> <label for="answer2"></label>
<input id="answer3" type="radio" name="answers"> <label for="answer3"></label>
<input id="answer4" type="radio" name="answers"> <label for="answer4"></label>
</fieldset>
<button id="submit" type="button" name="button">Submit</button>
<button id="back" type="button" name="button">Back</button>
</div>
Related
I made a searchbar filter and a filter with input buttons. The searchbar filter works but the input filter doesn't. How is that possible? Here you see the searchbar code and underneath there is the input button filter. First I made that filter with buttons who filter on the classnames but there are too many possibilities so with filtering on textContent it's the easiest I thought.
JavaScript
//searchbar
function liveSearch() {
let search_query = document.getElementById('myInput').value;
//Use innerText if all contents are visible
//Use textContent for including hidden elements
for (var i = 0; i < sheets.length; i++) {
if (
sheets[i].textContent.toLowerCase().includes(search_query.toLowerCase())
) {
sheets[i].classList.remove('is-hidden');
} else {
sheets[i].classList.add('is-hidden');
}
}
}
document.getElementById('myInput').oninput = liveSearch;
//buttons filter
let knop = document.querySelectorAll('#btn');
knop.forEach((btn) =>
btn.addEventListener('click', (e) => {
e.target.classList.toggle('active');
liveSearch2();
}),
);
function liveSearch2() {
let button = document.getElementById('btn').value;
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].textContent.toLowerCase().includes(button.toLowerCase())) {
sheets[i].classList.remove('is-hidden');
} else {
sheets[i].classList.add('is-hidden');
}
}
}
document.getElementById('btn').oninput = liveSearch2;
<input type="text" id="myInput" placeholder="Search for music..." title="Type in a name" />
<div id="myBtnContainer">
<p class="titeltje">Genre</p>
<input value="Barok" type="button" class="btn" id="btn"></input>
<input value="Classic" type="button" class="btn" id="btn"></input>
<input value="Rennaisance" type="button" class="btn" id="btn"></input>
<input value="Romantic" type="button" class="btn" id="btn"></input>
<input value="Movies" type="button" class="btn" id="btn"></input>
</div>`
You're always getting the value of the first button when you do
let button = document.getElementById('btn').value;
This doesn't get the button that the user clicked on.
Use e.target to get the button that the user clicked on, and get its value.
knop.forEach((btn) =>
btn.addEventListener('click', (e) => {
e.target.classList.toggle('active');
liveSearch2(e.target.value);
}),
);
function liveSearch2(button) {
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].textContent.toLowerCase().includes(button.toLowerCase())) {
sheets[i].classList.remove('is-hidden');
} else {
sheets[i].classList.add('is-hidden');
}
}
}
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I'm not sure why my localstorage isn't working. When the page loads, it loads up the function stored(), which should be the stored value for my toggle function, which changes the page from light to dark.
HTML:
<body onload="stored()">
<label for="ID_HERE" class="toggle-switchy" >
<input checked type="checkbox" name="server" id="ID_HERE">
<span class="toggle" onclick="toggle()" id="saveDarkLight"></span>
<span class="switch"></span>
</span>
</label>
(Removed old javascript file as it did not let me post too much code)
Updated HTML:
<label for="ID_HERE" class="toggle-switchy" >
<input checked onclick="toggle()" type="checkbox" name="server" id="ID_HERE">
<span class="toggle" id="saveDarkLight"></span>
<span class="switch"></span>
</span>
</label>
Updated JS:
function stored() {
var storedValue = localStorage.getItem("server");
if(storedValue){
lightmode()
document.getElementById("ID_HERE").checked = true;
}else{
darkmode()
document.getElementById("ID_HERE").checked = false;
}
}
function toggle() {
if(document.getElementById("ID_HERE").checked) {
lightmode()
var input = document.getElementById("ID_HERE");
localStorage.setItem("server", input.checked);
}
else {
darkmode()
var input = document.getElementById("ID_HERE");
localStorage.setItem("server", input.checked);
}
}
It is input.value and not input.val() in vanilla JavaScript. And your onclick should be on the input. I would do it like so :
function stored() {
var storedValue = localStorage.getItem("server");
if(sotoredValue){
lightmode()
document.getElementById("ID_HERE").checked = true;
}else{
darkmode()
document.getElementById("ID_HERE").checked = false;
}
}
function toggle() {
if(document.getElementById("ID_HERE").checked) {
lightmode()
var input = document.getElementById("ID_HERE");
localStorage.setItem("server", input.checked);
}
else {
darkmode()
var input = document.getElementById("ID_HERE");
localStorage.setItem("server", input.checked);
}
}
function darkmode() {
const bodyChanges = document.querySelectorAll('.margin_body');
for (let i = 0; i < bodyChanges.length; i++) {
bodyChanges[i].style.background = '#0c0a0f';
}
}
function lightmode() {
const bodyChanges = document.querySelectorAll('.margin_body');
for (let i = 0; i < bodyChanges.length; i++) {
bodyChanges[i].style.background = 'white';
}
}
<body onload="stored()">
<label for="ID_HERE" class="toggle-switchy" >
<input checked onclick="toggle()" name="server" id="ID_HERE">
</label>
</body>
This code successfully takes the contents of the form and saves it to an ordered list, 2 more functions do the same thing but instead create a timestamp. I'm trying to take every li element that gets generated and save it to localStorage when you push the save button and then repopulate it again from the local storage when you push the "load" button. I can't get it to work come hell or high water. The load button does nothing, and oddly enough the "save" button acts as a clear all and actually removes everything rather then saving it. Console log shows no errors. I have the JavaScript below and the corresponding HTML.
let item;
let text;
let newItem;
function todoList() {
item = document.getElementById("todoInput").value
text = document.createTextNode(item)
newItem = document.createElement("li")
newItem.onclick = function() {
this.parentNode.removeChild(this);
}
newItem.onmousemove = function() {
this.style.backgroundColor = "orange";
}
newItem.onmouseout = function() {
this.style.backgroundColor = "lightblue";
}
todoInput.onclick = function() {
this.value = ""
}
newItem.appendChild(text)
document.getElementById("todoList").appendChild(newItem)
};
function save() {
const fieldvalue = querySelectorAll('li').value;
localStorage.setItem('item', JSON.stringify(item));
}
function load() {
const storedvalue = JSON.parse(localStorage.getItem(item));
if (storedvalue) {
document.querySelectorAll('li').value = storedvalue;
}
}
<form id="todoForm">
<input id="todoInput" value="" size="15" placeholder="enter task here">
<button id="button" type="button" onClick="todoList()">Add task</button>
<button id="save" onclick="save()">Save</button>
<button id="load" onclick="load()">Load</button>
</form>
As #Phil and #Gary explained part of your problem is trying to use querySelectorAll('li') as if it would return a single value. You have to cycle through the array it returns.
Check the below code to give yourself a starting point. I had to rename some of your functions since they were causing me some errors.
<form id="todoForm">
<input id="todoInput" value="" size="15" placeholder="enter task here">
<button id="button" type="button" onClick="todoList()">Add task</button>
<button id="save" onclick="saveAll()" type="button">Save</button>
<button id="load" onclick="loadAll()" type="button">Load</button>
</form>
<div id="todoList"></div>
<script>
let item;
let text;
let newItem;
function todoList() {
item = document.getElementById("todoInput").value
text = document.createTextNode(item)
newItem = document.createElement("li")
newItem.onclick = function() {
this.parentNode.removeChild(this);
}
newItem.onmousemove = function() {
this.style.backgroundColor = "orange";
}
newItem.onmouseout = function() {
this.style.backgroundColor = "lightblue";
}
todoInput.onclick = function() {
this.value = ""
}
newItem.appendChild(text)
//Had to add the element
document.getElementById("todoList").appendChild(newItem);
}
function saveAll() {
//Create an array to store the li values
var toStorage = [];
var values = document.querySelectorAll('li');
//Cycle through the li array
for (var i = 0; i < values.length; i++) {
toStorage.push(values[i].innerHTML);
}
console.log(toStorage);
//Can´t test this on stackoverflow se the jsFiddle link
localStorage.setItem('items', JSON.stringify(toStorage));
console.log(localStorage);
}
function loadAll() {
const storedvalue = JSON.parse(localStorage.getItem('items'));
console.log(storedvalue);
//Load your list here
}
</script>
Check https://jsfiddle.net/nbe18k2u/ to see it working
Hello,
I am making a simple text changer website where I want the user to be able to select what options to use. Right now I have two options; myConvertOption which capitalizes every odd letter in a word and I have myScrambleOption which randomly mixes up each word a bit.
Right now whenever you click on Caps (checkbox_1) it already executes the function where I only want it to execute whenever the user clicks on the "Convert" button + it also puts spaces in between each letter now.
The Scramble button (checkbox_2) doesn't do anything for some reason, except for console logging the change.
JSfiddle: https://jsfiddle.net/MysteriousDuck/hLjytr2p/1/
Any help and suggestions will be greatly appreciated!
P.S I am new to Javascript.
Checkbox event listeners:
checkbox_1.addEventListener('change', function () {
console.log("checkbox_1 changed");
if (this.checked) {
myConvertFunction();
} else {
//Do nothing
}
})
checkbox_2.addEventListener('change', function () {
console.log("checkbox_2 changed");
if (this.checked) {
myScrambleFunction(text);
} else {
//Do nothing
}
})
Checkbox HTML:
<div class="checkbox">
<input type="checkbox" id="checkbox_1" >
<label for="checkbox_1">Caps</label>
</div>
<div class="checkbox">
<input type="checkbox" id="checkbox_2" >
<label for="checkbox_2">Scramble</label>
</div>
this works properly..
You just had to add the event on the button and then test which check box was checked, and other little things
<!doctype html>
<html>
<head>
</head>
<body>
<div class="container">
<h1> Text Changer </h1>
<h2> CAPS + randomize letters text changer</h2>
<div class="checkbox">
<input type="checkbox" id="checkbox_1">
<label for="checkbox_1">Caps</label>
</div>
<div class="checkbox">
<input type="checkbox" id="checkbox_2">
<label for="checkbox_2">Scramble</label>
</div>
<textarea type="text" autofocus="true" placeholder="input text" id="inputText" value="Input Value" spellcheck="false" style="width: 300px;"></textarea>
<button class="button button1" id="convertText">Convert</button>
<textarea type="text" placeholder="converted text" id="convertedText" value="Clear" readonly="true" spellcheck="false" style="width: 300px;"></textarea>
<button class="button button1" id="copyText">Copy</button>
</div>
<script>
var text = document.getElementById("inputText").value;
var convertText = document.getElementById("convertText");
var checkbox_2 = document.getElementById("checkbox_2");
var checkbox_1 = document.getElementById("checkbox_1");
//Capitalize every odd letter
function myConvertFunction() {
var x = document.getElementById("inputText").value;
var string = "";
for (let i = 0; i < x.length; i++) {
if (i % 2 == 0) {
string = string + x[i].toUpperCase();
} else {
string = string + x[i];;
}
}
return string;
}
//Scramble words
function myScrambleFunction(text) {
let words = text.split(" ");
words = words.map(word => {
if (word.length >= 3) {
return word.split('').sort(() => 0.7 - Math.random()).join('');
}
return word;
});
return words.join(' ');
}
document.getElementById("copyText").addEventListener("click", myCopyFunction);
//Copy textarea output
function myCopyFunction() {
var copyText = document.getElementById("convertedText");
copyText.select();
document.execCommand("copy");
alert("Copied the text: " + copyText.value);
eraseText();
}
//Delete textarea output
function eraseText() {
document.getElementById("convertedText").value = "";
document.getElementById("inputText").value = "";
document.getElementById("inputText").focus();
}
//don't add the event to the radio buttons (previously checkboxes), add it to the convert button, and in its function test which radio button has been checked
convertText.addEventListener('click', function() {
if (checkbox_1.checked && checkbox_2.checked) {
console.log("doing both options");
document.getElementById("convertedText").value = myScrambleFunction(myConvertFunction());
} else if (checkbox_2.checked) {
console.log("proceeding scrumble");
document.getElementById("convertedText").value = myScrambleFunction(text);
} else if (checkbox_1.checked) {
console.log("proceeding cap");
document.getElementById("convertedText").value = myConvertFunction();
}
})
</script>
</body>
</html>
You're never updating var text.
You need to update it before using it if you want the value to be something other than an empty string.
checkbox_2.addEventListener('change', function () {
console.log("checkbox_2 changed");
if (this.checked) {
text = document.getElementById("inputText").value;
myScrambleFunction(text);
} else {
//Do nothing
}
I have this code but it doesn't work:
HTML:
<button id="btn_search">Search</button>
<input id="srh" type="search">
JS:
var btnSearch = document.getElementById("btn_search");
var search = document.getElementById("srh");
if (document.addEventListener) {
btnSeach.addEventListener('click',activeSearch);
} else if (document.attackEvent) {
btnSearch.attackEvent('onclick',activeSearch);
}
function activeSearch (event) {
event.preventDefault();
if (search.style.width == '0') {
search.style.width = '14.8em';
search.style.opacity = '1';
} else if (search.style.width == '14.8em') {
search.style.width = '0';
search.style.opacity = '0';
}
I need a toggle button
What should I do?
I might think about using a CSS class and toggle() to show/hide you element.
var btnSearch = document.getElementById("btn_search");
btnSearch.addEventListener('click', function(event){
var search = document.getElementById("srh");
search.classList.toggle("hidden");
event.preventDefault();
});
#srh { width: 14.8em; }
#srh.hidden { display: none; }
<button id="btn_search">Search</button>
<input id="srh" type="search" />
You can simply use JQuery to simplify all the proccess. Make all the code as simple as:
function magictoggle(a) {
if (a == 1) {
$("#btn1").attr("onclick", "magictoggle(0)");
$("#searchbox").hide(1000);
//1000 Are the miliseconds will take the box to hide
} else {
$("#btn1").attr("onclick", "magictoggle(1)");
$("#searchbox").show(1000);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn1" onclick="magictoggle(1)">Search</button>
<input type="text" id="searchbox" placeholder="A search Box">