I'm making a quiz in Javascript and I want to be able to use the same button over and over for answers without reloading the page. Here's my code:
document.getElementById("nextBtn").addEventListener("click", function() {
let answers = document.getElementById('answers').value;
let inputAns = [0, 1, 2];
for (var i = 0; i < inputAns.length; i++) {
if (answers == inputAns[i]) {
document.getElementById("correctAnswers").innerHTML = "✅";
inputAns++;
} else {
document.getElementById("incorrectAnswers").innerHTML = "❌";
inputAns++;
}
}
});
and
<button type="submit" id="nextBtn" class="nextBtn">NEXT!</button>
</div>
<div class="correctAnswers" id="correctAnswers"></div>
<div class="incorrectAnswers" id="incorrectAnswers"></div>
So when the button (nextBtn) is pressed, it reads the input bar (answers) and checks to see if that matches the input of the array (inputAns). If it matches, a green check is displayed. If it doesn't, a red x is displayed. Then the loop adds to the array to make the answer change for the next question. This works one time. But when the button is pressed again, nothing happens. How can I make the function repeat so that more questions can be checked and checks or x's can appear? Thanks!
ETA: More HTML
The first thing you'll want to do is turn your .innerHTML to append rather than replace (with +=).
You'll also want to make use of a true equals in the conditional, or else an empty answer will be treated as the same thing as 0, and thus be valid for the first answer. If you do this, you'll also want to make use of parseInt(answers) rather than just answers.
After this, you'll want to shift your input array outside of your function, and set up a current answer variable as well. This should reference the first index of the array.
From here, you'll want to completely remove your loop, and simply run inputAns.shift() inside of your 'success' criteria; this will remove the first element in the array. Because of this, you're able to run the comparison against currentAnswer = inputAns[0]. If the first element is removed, the answer will be compared against the second element, and so on until all answers have been given.
Finally, you'll probably want to add a message or 'stop' condition when all answers have been entered. This can be done by checking if (!inputAns.length).
This can be seen in the following, where the correct answers are 0, 1, 12` in order:
let inputAns = [0, 1, 2];
let currentAnswer = inputAns[0];
document.getElementById("nextBtn").addEventListener("click", function() {
let answers = document.getElementById('answers').value;
if (parseInt(answers) === currentAnswer) {
document.getElementById("correctAnswers").innerHTML += "✅";
inputAns.shift();
if (!inputAns.length) {
console.log("All answers provided!");
}
} else {
document.getElementById("incorrectAnswers").innerHTML += "❌";
}
currentAnswer = inputAns[0];
});
<input id="answers" />
<button id="nextBtn">Next</button>
<div id="correctAnswers"></div>
<div id="incorrectAnswers"></div>
Related
How do I make it so that the numbers I input are all on top of one another and another together in one spacing.
It supposed to show all the 3 grades I have input and when the button is clicked it should show the average and either pass or fail (I know it's supposed to be an if else statement but I really can't comprehend the codes and where will I put it)
If someone helps me solve this one can someone give me more user input / function related exercises that I can work on? thanks.
var p = prompt ("enter first grade");
var c = prompt ("enter second");
var o = prompt ("enter third grade");
document.write (p);
document.write (c);
document.write (o);
function xxx (p,c,o)
{
document.getElementById("demo4").innerHTML = ((parseInt(p)+parseInt(c)+parseInt(o)) / 3)
}
<p id="demo"></p>
<p id="demo2"></p>
<p id="demo3"></p>
<button onclick="xxx()">calculate</button>
<p id="demo4"></p>
<p id="demo5"></p>
Let me start first with the main non-logic problems with your code:
You shouldn't use prompt, it's just bad user experience. Dynamically create HTML elements instead.
You shouldn't use document.write. You aren't able to specify where the text should go and it makes your code vulnerable towards XSS vulnerabilities.
You shouldn't use onclick. You should never mix the JS with your HTML like that. (React's HTML-like syntax is not HTML, it's JSX. It's okay to do that there.)
Now, back to the main logic which your code should follow.
Provide the user with one <input type='number'> field and an "Add" button.
Recalculate the result on every change, don't rely on a "Calculate" button to update your state.
You can use an if statement to detect a failing grade.
Here is an example of a more proper implementation of what you're trying to accomplish. I know I'm basically doing the homework task for you so I would like you to learn from this.
// Storing references to elements.
const grades = document.getElementById('grades');
const template = document.getElementById('template');
const addButton = document.getElementById('add');
const averageOut = document.getElementById('average');
const failedOut = document.getElementById('failed');
function recalculate() {
// Let's create a sum variable.
let sum = 0;
// Let's query the document for grade input fields.
const numberFields = document.querySelectorAll('#grades input');
// Iterate over number fields with for ... of.
for (let field of numberFields) {
// Unary + converts the value into a number.
// parseInt can be used instead as well.
sum += +field.value;
}
// .length gives you the total amount of input fields.
// .length works on any array and some lists. (querySelectorAll returns a NodeList instead of an array)
const average = sum/numberFields.length;
// Use innerText to prevent XSS.
averageOut.innerText = average;
// If statement to check if the person has failed.
if (average < 3.0) {
failedOut.innerText = 'FAIL';
} else {
failedOut.innerText = 'NOT FAIL';
}
}
// Let's recalculate the average on any change made in ANY field in the document.
// This is basically what jQuery does in its '.on(eventType, selector, listener)' method.
// This technique relies on event bubbling.
// Make sure to replace this once you start adding more functions into the document.
// Also, () => is a closure in JavaScript, which is a function but with a different context.
document.addEventListener('change', () => recalculate());
// Adding new fields.
addButton.addEventListener('click', () => {
// Clone the template...
const templateClone = template.cloneNode(true);
// ...and append it to our grades.
grades.appendChild(templateClone);
// Also recalculate.
recalculate();
});
// Recalculate on load.
recalculate();
<ul id="grades">
<li id="template">
<input type="number" value="1" min="1" max="5" />
</li>
</ul>
<button id="add">Add</button>
<div>
<span>Average:</span> <span id="average"></span>
</div>
<div>
<span>Failed?:</span> <span id="failed"></span>
</div>
What you could improve upon is adding a "Remove" button.
I have very delicate problem, I'll make an example. What am i doing is that I'm basically prepending elements and differentiating them by incrementing (i need to do it this way for certain reasons), then there is an option to click on any element and delete it.
This is only stupid example of what it looks like:
$(function () {
var i = 0;
$("#new").click(function(){
i++;
$("#container").prepend("<div class='prepended "+i+"'>blah blah blah</div>")
$(".prepended").click(function(){
$(this).remove();
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="new">click here</button>
<div id="container"></div>
When I delete any element, I need to somehow manage to make the incrementing "i" variable fill the missing element. I don't know how to explain in words so I'll explain in "code":
Let's say I prepended 6 elements so the "i" variable is now 6:
if(deleted_divs_class == 1)
{
i = 1; // fill the missing "1"
next_click_i = 6; // variable i on next click should be 6 in order to continue in right order
}
else if (deleted_divs_class !== 1 || 6) // deleted element is somewhere from middle so it's not 1 or 6
{
i = fill_missing_number; // fill the removed number
next_click_i = 6; // continue in right order
}
else
{
i--;
// deleted element is the last element of line so continue normally by incrementing
}
i know how to get deleted_divs_class variable and apply the next_click_i variable but i don't know how make the whole thing work dynamically
I know that this question might seems very weird but this is just an example, it's part of much much much bigger code and i just need to make logic of this "incrementation" in order to make the whole thing work properly as i need.
So i just can not figure out the logic.
I suppose I created the code you are looking for, but I’m not sure if I understood your question correctly. Look at this code. Is this what you wanted or not?
$(function () {
var missed=[]; //Here will be stored missed numbers
var i = 0;
$("#new").click(function(){
var n=0;
if(missed.length>0) {
n=missed.shift(); //get next missed number from the array
} else
n=++i;
$("#container").prepend("<div data-i='"+n+"' class='prepended "+n+"'>"+n+"blah blah blah</div>")
});
$('#container').on('click',".prepended",[], function(){
missed.push($(this).data('i')); //save removed number into missed numbers array
$(this).remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="new">click here</button>
<div id="container"></div>
To backfill the deleted i values, you'll need to store them. In this example, deleted_i holds all deleted values, and attempts to retrieve the new value from there first when creating a new element. If it's empty, it defaults to incrementing the value of i.
Note also that the click event is now bound to the container so that it only fires once - in your example, it was getting re-bound to all .prepended elements, so that when you clicked on one, it was firing that function as many times as the loop had run so far.
$(function () {
var i = 0,
deleted_i = []
$("#new").click(function(){
var idx;
console.log(deleted_i)
if(deleted_i.length) idx = deleted_i.shift() //grab the first deleted index, if one exists
else idx = ++i;
$("#container").prepend("<div data-index='"+idx+"' class='prepended "+idx+"'>blah blah blah this is "+idx+"</div>")
});
$("#container").click(function(e){
var $target = $(e.target)
if($target.hasClass('prepended')){
$target.remove();
deleted_i.push($target.attr('data-index'))
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="new">click here</button>
<div id="container"></div>
This is my code to create the textarea and it works fine, but I want to know how many textarea the user creates and their names.
function createBoxEquip() {
$codEquip = $('#equipamento').val();
$nomeEquip = $('#equipamento>option:selected').text();
$novadiv = "#div"+$codEquip;
if ( !$( $novadiv ).length ) {
$("#equip_tot").append('<div class="box"name=div'+$codEquip+'id=div'+$codEquip+'></div>')
$("#div"+$codEquip).append('<span class="titulo1" name='+$codEquip+' id='+$codEquip+'> - '+$nomeEquip+'</span><span name=texto'+$codEquip+' id=texto'+$codEquip+'><br> </span>');
$("#div"+$codEquip).append('<input type="button" name=apagar'+$codEquip+' id=apagar'+$codEquip+' value="Remover" onclick="deleteBoxEquip('+$codEquip+')"><span name=texto1'+$codEquip+' id=texto1'+$codEquip+'> <br></span>');
$("#div"+$codEquip).append('<input type="text" style="width: 20px;" name=contalinhas'+$codEquip+' id=contalinhas'+$codEquip+'><span name=texto2'+$codEquip+' id=texto2'+$codEquip+'><br></span>');*/
$("#div"+$codEquip).append('<textarea style="width: 150px;" rows=12 name=numerosserie'+$codEquip+' id=numerosserie'+$codEquip+' value="'+$codEquip+' - '+$nomeEquip+'"/><span name=texto3'+$codEquip+' id=texto3'+$codEquip+'> </span>');
}
}
As long as you can pre-determine what the names of the textarea will be, for example - I've written similar code that generated a bunch of <div> tags with unique ID's, each Id was numeric, so I'd auto-generate a bunch of tags like this:
<div id="div-0">Zero</div>
<div id="div-1">One</div>
<div id="div-2">Two</div>
Because I know in advance that each div id will have the prefix div- followed by a digit which begins at 0 and increments sequentially, I can iterate through each element in a loop, and know when I've reached an undefined element:
function loopElements() {
var divPrefix = "div-";
var divNo = 0;
// Loop through all div- tags:
//
while (true) {
// The .length property will return 0 if the element
// doesn't exist...
//
if ($("#" + divPrefix + divNo.toString()).length == 0)
// This div doesn't exist, bail!
//
break;
// do something with div
divNo++;
}
}
Something like this would work, it depends on the names/id's you're creating, and if you can somehow predetermine what they should be.
hope this helps.
EDIT:
Having read your question again I think the above solution may not be what you're looking for, if not I apologise.
There are some ambiguities with your question...exactly how are these names created? Does the user choose them? Are they generated programmatically?
You should post more code and explain in greater detail.
I have a standard html from with a couple of radio buttons (3 of them actually).
With:
function abo_show()
{
var x = document.gms_option.gms_element1;
console.log(x.value);
if (x.value = "1") {
document.getElementById("abo").style.display="block";
document.getElementById("gms_abo1").style.display="table-row";
document.getElementById("gms_abo2").style.display="table-row";
document.getElementById("gms_abo3").style.display="table-row";
}
else {
document.getElementById("abo").style.display="block";
document.getElementById("gms_abo1").style.display="table-row";
document.getElementById("gms_abo2").style.display="none";
document.getElementById("gms_abo3").style.display="none";
}
}
I try to show a couple of extra buttons, based on the first 3. The new ones are in a div "abo", that is hidden by default (in css: "display:none").
But when I click on a radio button to select, it executes and jumps to option 1.
No idea why. Could someone explain and help?
x.value = "1" because of this.
you use a single = doing an assignment not a comparison. This causes the if to always succeed. just use == or even ===instead.
You have an easy = in an if statement. Its not compared, it is set.
Your code sets x.value to "1" instead of comparing it.
Use:
if(x.value=="1") {
In Javascript, I'm trying to create a user script that will automatically click on a 'Blue Button'. Normally, I would do this:
var bluebutton = "document.getElementById("blue_button")"
if (bluebutton) {
bluebutton.onclick();
}
But NOW, the blue button does not have its own obvious ID. It's ID is randomized, and could be either button1, button2, or button3.
Here's the HTML that I'm talking about:
<div class="button_slot">
<div id="button1" style="cursor:pointer; padding-left:30px" onclick="buttonsubmit('button1')" onmouseover="infopane.display('Blue Button','I'm a blue button!')" onmouseout="infopane.clear()">
<div class="button_slot">
<div id="button2" style="cursor:pointer; padding-left:30px" onclick="buttonsubmit('button2')" onmouseover="infopane.display('Red Button','I'm a red button!')" onmouseout="infopane.clear()">
<div class="button_slot">
<div id="button3" style="cursor:pointer; padding-left:30px" onclick="buttonsubmit('button3')" onmouseover="infopane.display('Yellow Button','I'm a yellow button!')" onmouseout="infopane.clear()">
After a bit of reading, I've concluded that the only way to direct my onclick() to the correct element/string is by using ".toString().match(name)" as shown below:
function clickbutton(name) {
var button_list = document.querySelectorAll('.button_slot > div');
for (var i=0; i<button_list.length; i++) {
var button = button_list[i];
if (button.onmouseover && button.onmouseover.toString().match(name)) {
button.onmouseover();
button.onclick();
break;
}
}
}
clickbutton('Blue');
(note: sometimes I use clickbutton('Red'); or clickbutton('Yellow'); just to experiemen)
Now here's the problem. This method works so horribly... Sometimes, my script completely misses the button (as in, nothing gets clicked) EVEN THOUGH there is definitely a string with the word 'Blue' in it.
If someone could identify what I'm doing wrong, or perhaps even suggest a more effective method, I would appreciate it so much! Thank you!
First, I'm not sure why you can't give each button an ID which corresponds to it's color, because I believe that would be the easiest way to achieve this. But assuming that, for some reason, your button ID's must be randomized (or for that matter, maybe they don't even have an ID).
In this case, what I would do is give each button a data-button-type attribute, for instance:
<div data-button-type="Blue" id="..." style="..." onclick="..." onmouseover="..." onmouseout="...">
Now, I can check the attribute when looking for which button to click, for example:
function clickbutton(name) {
var button_list = document.querySelectorAll('.button_slot > div');
for (var i=0; i<button_list.length; i++) {
var button = button_list[i];
if (button.getAttribute('data-button-type') == name) {
button.onmouseover();
button.onclick();
break;
}
}
}
clickbutton('Blue');
I'm pretty sure you want to use indexOf although I think its most likely a timing issue.
First just try invoking it in a setTimeout function, so the document has (probably) loaded fully when you execute. It would explain it sometimes working sometimes not.
setTimeout(function(){ clickbutton(name) }, 3000);
I would do:
var clickButton = function(name){
var button_list = document.querySelectorAll('.button_slot > div');
for(var i = 0; i < button_list.length; i++){
var button = button_list[i];
if(button.getAttribute('onmouseover').indexOf(name) !== -1){
button.onclick.apply(); // They seem to have parameters in your example?
}
break;
}
}
setTimeout(function(){ clickButton('blah') }, 3000);
As a first attempt...