I am trying to make a correct and incorrect question counter that shows groups of 4.
If I click on the first correct answer the counter works correctly and increases as I click, but it does not work with the second correct answer. The same happens with the wrong answers
This is the codes that I use, anyone could help me? Thx
HTML CODE:
¿Which of the following operations results in 8?
<input class="solucioncorrecta" value="6+2">
<input class="solucioncorrecta" value="7+1">
<input class="solucionincorrecta" value="1+1">
<input class="solucionincorrecta" value="2+2">
And the JS CODE:
<!-- CONTADOR FALLOS TEST -->
<script type="text/javascript">
var root = document.querySelector('.solucionincorrecta');
root.onclick = function() {
var elem = document.getElementById('contadorfallos');
elem.innerHTML = +elem.innerText + 1;
};
</script>
<!-- CONTADOR FALLOS TEST -->
<!-- CONTADOR ACIERTOS TEST -->
<script type="text/javascript">
var root = document.querySelector('.solucioncorrecta');
root.onclick = function() {
var elem = document.getElementById('contadoraciertos');
elem.innerHTML = +elem.innerText + 1;
};
</script>
The issue is that you are using document.querySelector() and not document.querySelectorAll()
document.querySelector() Returns the first match
document.querySelectorAll() Returns all matches
As a result, you are only setting an onclick property on the first .correcta and .incorrecta elements, not all of them.
To set this on all of them, you need to do two things:
You need use document.querySelectorAll() instead of document.querySelector(). This returns a list (specifically, a NodeList) of matching elements.
Loop over the items in your list, and attach onclick handlers to each of them. There are many ways to loop over a NodeList, listed here.
Here is an example:
// get all incorrect elements
var incorrectElements = document.querySelectorAll('.incorrecta');
// loop over each elements
for (var element of incorrectElements) {
// add an onclick
element.onclick = incorrectClickHandler
}
// this is the function being called by onclick
function incorrectClickHandler() {
score.innerText = parseInt(score.innerText) - 1;
}
It would be better if you upload your full codes. But anyway I write you some notes that probably answer your question.
-dont use the same name (root) for your .correcta and .incorrecta
-in your second <script>, you didnt defined button as an object . So browser cant understand it.
Related
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>
I am making a webpage that has a baseball strikezone with 25 buttons that will be clickable in 25 locations. I need to know if there is a easier way to do this then what I am doing. Maybe something that will take up far less lines. The button is clicked and then the counter is added by one to another table.
$('#one').click(function(){
counter++;
$('#ones').text(counter);
});
var countertwo = 0;
$('#two').click(function(){
countertwo ++;
$('#twos').text(countertwo);
});
A bit of a guess here, but:
You can store the counter on the button itself.
If you do, and you give the buttons a common class (or some other way to group them), you can have one click handler handle all of them.
You can probably find the other element that you're updating using a structural CSS query rather than id values.
But relying on those ID values:
$(".the-common-class").click(function() {
// Get a jQuery wrapper for this element.
var $this = $(this);
// Get its counter, if it has one, or 0 if it doesn't, and add one to it
var counter = ($this.data("counter") || 0) + 1;
// Store the result
$this.data("counter", counter);
// Show that in the other element, basing the ID of what we look for
// on this element's ID plus "s"
$("#" + this.id + "s").text(counter);
});
That last bit, relating the elements by ID naming convention, is the weakest bit and could almost certainly be made much better with more information about your structure.
You can use something like this:
<button class="button" data-location="ones">One</button>
...
<button class="button" data-location="twenties">Twenty</button>
<div id="ones" class="location">0</div>
...
<div id="twenties" class="location">0</div>
$('.button').on('click', function() {
var locationId = $(this).data('location')
, $location = $('#' + locationId);
$location.text(parseInt($location.text()) + 1);
});
Also see this code on JsFiddle
More clean solution with automatic counter
/* JS */
$(function() {
var $buttons = $('.withCounter'),
counters = [];
function increaseCounter() {
var whichCounter = $buttons.index(this)+1;
counters[whichCounter] = counters[whichCounter] ? counters[whichCounter] += 1 : 1;
$("#counter"+whichCounter).text(counters[whichCounter]);
}
$buttons.click(increaseCounter);
});
<!-- HTML -->
<button class="withCounter">One</button>
<button class="withCounter">Two</button>
<button class="withCounter">Three</button>
<button class="withCounter">Four</button>
<p id="counter1">0</p>
<p id="counter2">0</p>
<p id="counter3">0</p>
<p id="counter4">0</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I've spent the past couple hours googling and browsing W3Schools and couldn't find a way to do exactly what I wanted. I've found similar articles but they don't answer my question perfectly.
So what I'm trying to do is this, create a JS function that when called in HTML will take the information given to return the appropriate information. E.G, I want there to be two HTML buttons. If the user presses the first button, it calls the function "onclick='show(x, y)'" and x and y which stand for another paragraph and an image. If the user presses the second button, it calls the same function with different variables "onclick='show(x, z)'" which would display the same paragraph as the other button would but would display a different image.
Basically, is it possible for HTML elements to have IDs that can be variable in JS so I that I do not have to create an individual JS function for every single button?
My Javascript:
<script>
var Show = function(elID, elID2) {
var el1 = document.getElementByID(elID);
var el2 = document.getElementByID(elID2);
var both = (elID) + " " + (elID2);
document.getElementById(elID).innerHTML = both;
}
</script>
My HTML:
<p id="demo">
<button onclick="Show(77, demo)">Click to convert</button>
</p>
I am still learning the ins and outs of Javascript so any and all help would be appreciated.
yes, enclose the arguments in quotes
<button onclick="Show('77', 'demo')">Click to convert</button>
without quotes 77 will be passed correctly but demo will not be since it will look for a demo property in window scope.
You should get innerHTML before inserting. Also note that, you must pass id attributes wrapped in quotes(').
ID attributes should at least have one character and it should not start with NUMBER
function Show(elID, elID2) {
var el1 = document.getElementByID(elID).innerHTML;
var el2 = document.getElementByID(elID2).innerHTML;
var both = (elID) + " " + (elID2);
document.getElementById(elID).innerHTML = both;
}
<p id="demo">
<button onclick="Show('77', 'demo')">Click to convert</button>
</p>
You could lay aside the inline JavaScript and opt for a different way, separating your markup from your logic.
https://jsfiddle.net/tricon/p2esv818/
HTML:
<button id="button" data-parameter-one='{ "keyOne": "valueOne", "keyTwo": "valueTwo" }'>
Some button
</button>
JavaScript:
var button = document.getElementById("button");
button.addEventListener("click", function() {
var parameters = this.getAttribute("data-parameter-one");
parameters = JSON.parse(parameters);
console.log(parameters);
});
I have a requirement where I have to pickup the last .div within a container and apply some business logic to it. The selection of the last .div has to be dynamic because the user has the option to add/remove .div elements.
Initially I tried with querySelectorAll but it did not seem to work. So I decided to change it to getElementsByClassName and surprisingly it worked with the same logic. Can somebody please help me with the reason for why the remove_div doesn't work while the second one (remove_div_2) does?
Note: I am not looking for a fix/solution to the issue because I have already proceeded with the second option. I just want to know the reason why the option with querySelectorAll doesn't work.
Below is my code:
HTML:
<div id='container'>
<div id='div1' class='div'>This is Div 1</div>
<div id='div2' class='div'>This is Div 2</div>
<div id='div3' class='div'>This is Div 3</div>
</div>
<button type='button' id='append_div'>Append Div</button>
<button type='button' id='remove_div'>Remove Div</button>
<button type='button' id='remove_div_2'>Remove Div 2</button>
JavaScript:
window.onload = function () {
var elementToStyle = document.querySelectorAll("#container .div");
elementToStyle[elementToStyle.length - 1].classList.add('red');
document.getElementById('append_div').onclick = function () {
var divToInsert = document.createElement('div');
divToInsert.id = 'new_div';
divToInsert.className = 'div';
divToInsert.innerHTML = 'This is an appended div';
document.getElementById('container').appendChild(divToInsert);
var elToStyle = document.querySelectorAll("#container .div");
for (i = 0; i < elToStyle.length; i++)
elToStyle[i].classList.remove('red');
elToStyle[elToStyle.length - 1].classList.add('red');
};
document.getElementById('remove_div').onclick = function () {
var elToStyle = document.querySelectorAll("#container .div");
document.getElementById('container').removeChild(elToStyle[elToStyle.length - 1]);
elToStyle[elToStyle.length - 1].classList.add('red');
};
document.getElementById('remove_div_2').onclick = function () {
var elToStyle = document.getElementsByClassName('div');
document.getElementById('container').removeChild(elToStyle[elToStyle.length - 1]);
elToStyle[elToStyle.length - 1].classList.add('red');
};
}
The reason is because querySelectorAll method returns a static list. Any changes made to the document after the querySelectorAll is used (like removeChild in this case) will not be reflected in the list of nodes returned. Hence elToStyle[elToStyle.length - 1] would still point to the node that was removed.
Whereas, getElementsByClassName on the other hand returns a live list of nodes. This implies that elToStyle[elToStyle.length - 1] would always point to the last .div irrespective of any changes were done to the document after the node list was prepared or not.
Below is the extract from the official documentation available here
The NodeList object returned by the querySelectorAll() method must be
static, not live ([DOM-LEVEL-3-CORE], section 1.1.1). Subsequent
changes to the structure of the underlying document must not be
reflected in the NodeList object. This means that the object will
instead contain a list of matching Element nodes that were in the
document at the time the list was created.
Note: You can see this by doing a console.log(elToStyle); both before and after the removeChild.
If you want to reference the last division element just do the following...
var id = 'container';
var d = document.getElementById(id).getElementsByTagName('div')
var lastDiv = d[d.length - 1];
..and then apply your querySelector.
so basically here is my script:
http://jsfiddle.net/JJFap/42/
Code -
jQuery(document).ready(function() {
var rel = new Array();
var count = 0;
jQuery(".setting").each(function() {
rel[count] = [];
if(jQuery("span").attr("rel")) {
rel[count].push(jQuery("span").attr("rel"));
}
console.log(count);
count++;
});
jQuery("body").text(rel);
console.log(rel);
});
and
<div class="setting">
<span rel="Variable">Variable</span>
<span rel="Item">Item</span>
<span rel="Something">Something</span>
</div>
<div>
<span rel="Smth">Smth</span>
<span>Sec</span>
</div>
<div class="setting">
<span>Second</span>
<span rel="first">First</span>
<span rel="Third">Third</span>
</div>
my question, is why does it display Variable, variable?
I would like it to display Variable, First, but I'm not able to do.
Basically what I would like to achieve is create new array, in which insert each div.setting span elements with rel attribute array.
So basically in this example it should output -
Array (
Array[0] => "Variable","Item","Something";
Array[1] => "first","Third";
)
Hope you understood what I meant :)
EDIT:
In my other example I tried to add jQuery("span").each(function() ... inside first each function, but it outputted two full arrays of all span elements with rel. I can't have different classes / ids for each div element, since all will have same class.
jQuery('span') is going to find ALL spans in your page, and then pull out the rel attribute of the first one. Since you don't provide a context for that span search, you'll always get the same #1 span in the document.
You should be using this:
jQuery('span',this).each(function() {
rel[count] = [];
if (jQuery(this).attr("rel")) {
rel[count].push(jQuery(this).attr("rel"));
}
console.log(count);
count++;
})
instead of this:
rel[count] = [];
if(jQuery("span").attr("rel")) {
rel[count].push(jQuery("span").attr("rel"));
}
console.log(count);
count++;
http://jsfiddle.net/mblase75/JJFap/52/
The trick is to use a second .each to loop over all the span tags inside each <div class="setting"> -- your original code was using jQuery("span"), which would just grab the first span tag in the document every time.
In addition to what has been said, you can also get rid of the count and one push() when using jQuery.fn.map() as well as getting rid of the if when adding [rel] to the selector:
jQuery(document).ready(function() {
var rel = [];
jQuery(".setting").each(function() {
rel.push(jQuery(this).find('span[rel]').map(function() {
return this.getAttribute('rel');
}).get());
});
jQuery("body").text(rel);
console.log(rel);
});
Within the .each() method, you have this code a couple times: jQuery("span").attr("rel"). That code simply looks for ALL span tags on the page. When you stick it inside the .push() method, it's just going to push the value for the rel attribute of the first jQuery object in the collection. Instead, you want to do something like $(this).find('span'). This will cause it to look for any span tags that are descendants of the current .setting element that the .each() method is iterating over.