I am using Javascript (not familiar with frameworks like Angular just yet), and trying to get and display the value of a number input from my HTML, but when I run the function that does this, the default value of "1" from the HTML seems to be the only one used, even if I change the input on the website itself to, say, 10 by clicking the arrows.
I think I've written the code correctly as far as syntax goes, so my only thought is that perhaps the input has to be wrapped in a form of some kind, and the "roll" button changed to type="submit"?
Here is a link to a codepen with the broken code, and some snippets of the involved pieces below.
var displayScreen = document.getElementById("display-message");
var rollButton = document.getElementById("roll-button");
//Variable to tell the rollDice() function how many times to roll dice.
var numDice = document.getElementById("num-dice").value;
//Dice Array to hold the results of the rollDice() function, gets cleared after each use.
var diceTotal = [];
//Event listener for the "roll" button
rollButton.addEventListener("click", rollDice);
//Make this function display a roll result
function displayMessage() {
displayScreen.innerText = diceTotal[0];
}
//Generate a random number between 1 and diceType, and set the rolledNumber variable to its result
function rollDice() {
//Nothing currently changes numDice, so it keeps default value="1".
result = 0;
var roll = Math.floor(Math.random() * diceType) + 1;
for (var i = 0; i < numDice; i++) {
result += roll;
}
diceTotal[0] = result;
displayMessage();
}
<div id="dice-display-div">
<!--
We want to display the dice roll total, any applied bonuses, and then the final total
together in this div, possibly as separate <h2> elements.
-->
<h2 id="display-message">Click "Roll" to Begin</h2>
</div>
<div id="roll-button-div">
<label class="roll-button-label" for="num-dice" id="num-dice-label">Number of Dice: </label>
<input class="roll-button-item" type="number" id="num-dice" name="num-dice" value="1" min="1" max="10">
<label class="roll-button-label" for="bonus" id="bonus-label">Bonus (or Negative): </label>
<input class="roll-button-item" type="number" id="bonus" name="bonus" value="0" min="-10" max="10">
<button class="roll-button-item" id="roll-button">Roll</button>
</div>
First, you should call your Math.random() inside the for loop, otherwise you will only randomly generate one number, and all your dice will have that same number. Second, you should assign numDice inside your function so it rechecks and assigns the current value instead of at the start of page render:
var displayScreen = document.getElementById("display-message");
var rollButton = document.getElementById("roll-button");
//Dice Array to hold the results of the rollDice() function, gets cleared after each use.
var diceTotal = [];
//Event listener for the "roll" button
rollButton.addEventListener("click", rollDice);
//Make this function display a roll result
function displayMessage() {
displayScreen.innerText = diceTotal[0];
}
//Generate a random number between 1 and diceType, and set the rolledNumber variable to its result
function rollDice() {
//Variable to tell the rollDice() function how many times to roll dice.
var numDice = document.getElementById("num-dice").value; //assign this upon function call so it checks it each time the button is clicked to get the latest value
//Nothing currently changes numDice, so it keeps default value="1".
result = 0;
var roll = 0
for (var i = 0; i < numDice; i++) {
roll = Math.floor(Math.random() * diceType) + 1; //call random on each dice roll
result += roll;
}
diceTotal[0] = result;
displayMessage();
}
Related
The Problem:
I can't seem to be able to get a list of buttons to change the value of their corresponding inputs.
I'm trying to code a cart system for my website, pretty standard. It involves a list of item, each of which have a section that includes two buttons for adding or subtracting the quantity of its corresponding item. These buttons surround the input that displays the current quantity (disabled so that the user must use the buttons to control it).
Everything is working, but I can't seem to figure out how to target the corresponding input of a button that is clicked so that it will change the value of that specific input.
What I've Tried:
I've figured out that if I add a [0] at the end of the "quantityInputs" variable then it will target the first input in the list, makes sense. But I don't want it to only target the first input, I want it to target the input that the button is associated with. Even then, when I test the plus button it only updates the input one time to 2 and then stops, which I only know because I'm printing the value to the console - it doesn't actually change the display on the webpage.
I've considered using a for loop to get the position of the input, but I'm not sure how to incorporate that into the code in order for it to work with the for loop that gets the position of the plus or minus buttons, or if that will even work.
Can anyone please help me out? I'd really appreciate it.
My Code:
HTML:
if (document.readyState == 'loading') {
document.addEventListener('DOMContentLoaded', ready)
} else {
changeQuantity()
}
function changeQuantity() {
var buttonUps = document.getElementsByClassName('item-quantity-up')
console.log('There are ' + buttonUps.length + ' plus buttons total.') // Tells you how many plus buttons there are.
for (var i = 0; i < buttonUps.length; i++) { // Get the positions of each plus button.
var button = buttonUps[i]
button.addEventListener('click', addQuantity) // When a plus button is clicked, run the addQuantity function.
}
var buttonDowns = document.getElementsByClassName('item-quantity-down')
console.log('There are ' + buttonDowns.length + ' minus buttons total.') // Tells you how many minus buttons there are.
for (var i = 0; i < buttonDowns.length; i++) { // Get the positions of each minus button.
var button = buttonDowns[i]
button.addEventListener('click', subQuantity) // When a minus button is clicked, run the subQuantity function.
}
}
function addQuantity(event) {
var quantityInputs = document.getElementsByClassName('cart-item-quantity') // Needs an index such as [0] in order to return a real number.
var inputValue = parseInt(quantityInputs.value) // Turns the value into an integer.
var max = quantityInputs.max // Retrieves the max value for the input.
if (inputValue >= max) {
inputValue = inputValue // If the quantity is greater than or equal to the max, then don't change the quantity.
} else {
inputValue = inputValue + 1 // If the quantity is less than the max, then add 1 to the quantity.
console.log(inputValue)
}
}
function subQuantity(event) {
var quantityInputs = document.getElementsByClassName('cart-item-quantity') // Needs an index such as [0] in order to return a real number.
var inputValue = parseInt(quantityInputs.value) // Turns the value into an integer.
var min = quantityInputs.min // Retrieves the min value for the input.
if (inputValue <= min) {
inputValue = inputValue // If the quantity is less than or equal to the min, then don't change the quantity.
} else {
inputValue = inputValue - 1 // If the quantity is greater than the min, then subtract one from the quantity.
console.log(inputValue)
}
}
<div class="cart-quantity-field">
<button class="item-quantity-down">-</button>
<input class="cart-item-quantity" type="number" min="1" max="20" value="1" disabled>
<button class="item-quantity-up">+</button>
</div>
You can manipulate the correct input field by doing the following:
On quantity-button click:
locate the clicked button's parent element
inside that parent, look for input with the correct class name
decide whether the button clicked should add or subtract one
add +1 or -1 respectively to the current value of the input
const allQuantityBtns = document.getElementsByClassName("quantity-btn");
Array.from(allQuantityBtns).forEach(btn => {
btn.addEventListener("click", e => {
const inputToChange = e.target.parentElement.querySelector(".cart-item-quantity");
const plusOrMinusOne = e.target.classList.contains("item-quantity-up") ? 1 : -1;
const newValue = parseInt(inputToChange.value) + plusOrMinusOne;
// validate newValue here. Eg: is it allowed to be smaller than zero?
inputToChange.value = newValue;
});
});
<div class="cart-quantity-field">
<button class="item-quantity-down quantity-btn">-</button>
<input class="cart-item-quantity" type="number" min="1" max="20" value="1" disabled>
<button class="item-quantity-up quantity-btn">+</button>
</div>
Note: you may wish to implement some validation:
stop the quantity from being too large or small before modifying the input's value
I am writing a little clicking game with javascript at the moment and I am currently stuck with a little challenge. I need it so that whenever i have clicked a button 10 times. my second value should increase by one. Maybe a little bit hard to understand, I'll try to explain it in code.
// Let's just say I have this variable.
var timesThatTheButtonHasBeenClickedTenTimes = 0;
// So let's say I have an amount of times clicked.
Amount = 0;
// Whenever I click the button..The Amount increases like this.
Amount++;
// so after one click the amount should be..
Amount = 1;
// I need it so that when the button has been clicked 10 times I want to display //that. Something like this.
timesThatTheButtonHasBeenClickedTenTimes = 1;
Should I do this with a while loop or what.
// Let's just say I have this variable.
var timesThatTheButtonHasBeenClickedTenTimes = 0;
// So let's say I have an amount of times clicked.
var amount = 0;
var counter = function () {
amount++;
if (amount === 10) {
amount = 0;
timesThatTheButtonHasBeenClickedTenTimes++;
}
document.getElementById('clicks').innerHTML = amount;
document.getElementById('hits').innerHTML = timesThatTheButtonHasBeenClickedTenTimes;
};
document.getElementById("mybutton").addEventListener("click", counter);
<button id='mybutton'>
Click me!
</button>
<p>
Clicks = <span id='clicks'>0</span>
</p>
<p>
10 times hits = <span id='hits'>0</span>
</p>
Hope it helps!
You could do something like:
var timesButtonClicked = 0;
var secondValue = 0;
if (timesButtonClicked === 10) {
secondValue++;
timesButtonClicked = 0;
} else {
timesButtonClicked++;
}
This is the very simple solution for you problem:
var clicks = 0;
Clicker = function() {
clicks++;
console.log('You clicked '+clicks+' times already.');
if(clicks == 10){
alert('Something what you want to alert.')
clicks = 0;
}
}
<button onclick="Clicker()">
Click me 10x times pls
</button>
One approach I'd suggest is:
function increment() {
// find the current number of times the <button> has been clicked,
// if the <button> has a data-current attribute we retrieve that
// attribute-value and parse it as a number in decimal format;
// if it does not have that custom data-* attribute we set the
// variable to 0:
let currentValue = this.dataset.current ? parseInt(this.dataset.current, 10) : 0;
// here we update the data-current attribute to the incremented value
// of the currentValue:
this.dataset.current = ++currentValue;
// we retrieve the element with the id of 'clicks', and set
// its textContent to the value held by the currentValue:
document.getElementById('clicks').textContent = currentValue;
// here we retrieve the element with an id of 'numberOfTens',
// and set its textContent to the floored value of the currentValue
// divided by 10:
document.getElementById('numberOfTens').textContent = Math.floor(currentValue / 10);
}
// here we retrieve the element with the id of 'clicker':
document.getElementById('clicker')
// and bind the increment() function (note the deliberate lack of
// parentheses) as the event-handler for the 'click' event:
.addEventListener('click', increment);
div:empty::before {
content: '0';
}
#clicks::after {
content: ' clicks.';
}
#numberOfTens::after {
content: ' tens of clicks.';
}
<button id="clicker">Click</button>
<div id="clicks"></div>
<div id="numberOfTens"></div>
References:
CSS:
:empty pseudo-class.
Pseudo-elements, ::before, ::after.
content property.
JavaScript:
document.getElementById().
EventTarget.addEventListener().
HTMLElement.dataset.
parseInt.
Pre-increment variable ++variableName.
I'm having trouble displaying the average number of clicks per round a user does for a challenge. When I go into the console I am able to calculate the average number, but I can't seem to figure out how to get it to display.
JFiddle:
https://jsfiddle.net/tglas/tkL4p8on/5/
My CSS:
<div>
round:<span id="rounds">1</span>
</div>
<div >
clicks:<span id="clicks">0</span>
</div>
<div>
Average:<span id="avgDisplay">0</span>
</div>
<button id="reset">
New Round
</button>
<button id="option1">
Option 1
</button>
<button id="option2">
Option 2
</button>
And JS:
var roundsDisplay = document.querySelector("#rounds");
var clicksDisplay = document.querySelector("#clicks");
var option1 = document.querySelector("#option1")
var option2 = document.querySelector("#option2");
var reset = document.querySelector("#reset")
var rounds = 1;
var clicks = 0;
var avg = clicks / rounds;
option1.addEventListener("click", function() {
clicks++;
clicksDisplay.innerHTML = clicks;
})
option2.addEventListener("click", function() {
clicks++;
clicksDisplay.innerHTML = clicks;
})
reset.addEventListener("click", function() {
rounds++;
roundsDisplay.innerHTML = rounds;
})
avgDisplay.innerHTML = avg;
I know I am probably missing something fundamental here, but I'm new to programming and would appreciate any help figuring out this concept.
You're just calculating the average one time, the first time your JS file runs. But you want to calculate the average every time you increase the counter.
Just create a function that calculates the average value every time a button is pressed and create a avgDisplay variable. (Like Olivier mentioned in the comments)
var avgDisplay = document.querySelector("#avgDisplay");
function updateAverage() {
avgDisplay.innerHTML = clicks / rounds;
}
and add it to your event callbacks after you've increased the counter
e.g.
option2.addEventListener("click", function() {
clicks++;
clicksDisplay.innerHTML = clicks;
updateAverage();
})
I got a problem while writung a code for a Heatmap based on link clicks.
I have a Page with different articel teasers. When i click the link the artical itself opensup. Now i want to track in real time how often which articel is clicked so i can decide which articel is relevant to users and place it like on the first articel space and so on.
Therefor i wrote a function which tracks the clicks with a counter and show them in the div.
Now my problem is. That i cant write like 20 functions for counters and 20 for resets. I want to have one function which can decide which articel was clicked and add +1 to the counter of the link.
My Code for the counter and the reset + the link text gets red after more than 5 clicks.
var count1 = 0;
function heatmap(id) {
if(id==1){
count1++;
document.getElementById("count1").innerHTML = count1;
}
if(count1>=5){
document.getElementById("link1").style.color = "red";
}
}
function reset(id){
if(id==1){
count1=0;
document.getElementById("count1").innerHTML = 0;
}
}
My html code so far
<div style="text-align:center; font-size:20px; font-family: arial;">
<div id="link1" onclick="heatmap(1)">This is the first Link</div><br>
<div id="count1">0</div><br>
<button onclick="reset(1)">RESET</button>
<button onclick="save(1)">SAVE</button>
</div>
Now my main problem is that i only want one function for all the link tracking.
Is there a possibiblity to write the code in a way the variables are dynamicly so that the function can decide which link was clicked.
for example something like:
var count + ID = 0;
function heatmap(ID) {
count + ID ++;
document.getElementById("count" + ID).innerHTML = count+ID;
}
if(count + ID >=5){
document.getElementById("link + ID").style.color = "red";
}
}
function reset(id){
count + ID =0;
document.getElementById("count + ID").innerHTML = 0;
}
}
I already searched this homepage and did some google searches but all i found was working with arrays or lists. But i think this wouldnt realy work for me since i want to give my function an ID and later add this id to the varibale name like count + ID = count | count + ID = count2 same with the document.getElementById("count" + ID).innerHTML = count+ID; = document.getElementById("count1").innerHTML = count1;
As you can see the link got a onclick="heatmap(ID)" this ID will be added to every articel Link and will go from the first articel with 1 to the last articel with like 20.
If i change an Articel the counter will be resetet and the ID will be changed to its position. So there will always be a identifier with the ID which can be used for the counter.
You could loop through all articles and store a counter on each element which you update or reset once the specific button inside the article was clicked:
var articles = document.querySelectorAll('article');
for(var i=0; i < articles.length; i++) {
articles[i].querySelector('.save').addEventListener('click', updateCounter);
articles[i].querySelector('.reset').addEventListener('click', resetCounter);
articles[i]['counter'] = 0;
}
function updateCounter(ev) {
var article = ev.target.parentNode;
article.counter++;
article.querySelector('.counter').innerHTML = article.counter;
/* Some server synchronisation should go here */
}
function resetCounter(ev) {
var article = ev.target.parentNode;
article.counter = 0;
article.querySelector('.counter').innerHTML = article.counter;
/* Some server synchronisation should go here */
}
DEMO
But to permanently store the counters you have to synchronize your results with a server, respectively a database.
If you just want to use one function you could realize it like this:
var articles = document.querySelectorAll('article');
for(var i=0; i < articles.length; i++) {
articles[i].querySelector('.save').addEventListener('click', checkCounter);
articles[i].querySelector('.reset').addEventListener('click', checkCounter);
articles[i]['counter'] = 0;
}
function checkCounter(ev) {
var article = ev.target.parentNode,
button = ev.target;
if(button.classList[0] === 'save') {
article.counter++;
} else if(button.classList[0] === 'reset') {
article.counter = 0;
}
article.querySelector('.counter').innerHTML = article.counter;
}
DEMO
First, please take a look at my fiddle.
I'm trying to figure out a clean way of making the price next to each item change when any item is selected (in that group, you can image that there will be graphics cards etc in a different section which also will need the same functionality).
If its positive I need the class to be .positive and vice versa, and if the item is selected (+0) then the price difference wont be displayed.
This will also be used on checkbox's.
Non-working example.
You'll want to compare each selected item with items having the same name. In the .each() loop in CalculatePrice(), pass the checked item to this function:
function CalculateDiffs(item) {
var selectedPrice = +item.data("price");
item.siblings(".item_price").text("");
$(".calculation-item[name='"+item.attr("name")+"']").not(item).each(function(){
var price = +$(this).data("price");
var diff = (price-selectedPrice).toFixed(2);
if (diff >= 0) {
diff = "+"+diff;
}
$(this).siblings(".item_price").toggleClass("negative", diff < 0).text(diff);
});
}
As for checkboxes, the above function will take care of hiding the price when it is checked. To display the prices for unchecked checkboxes:
$(".calculation-item:checkbox:not(:checked)").each(function(){
$(this).siblings(".item_price").text("+"+$(this).data("price"));
});
Or, if you want to display the price of a checked checkbox as negative, use this instead:
$(".calculation-item:checkbox").each(function(){
var diff = (this.checked ? "-" : "+") + $(this).data("price");
$(this).siblings(".item_price").toggleClass("negative",this.checked).text(diff);
});
http://jsfiddle.net/gilly3/HpEJf/8/
Actually it's pretty straight forward, all you'll need to do is calculate the difference between the selected price and the price of all the options in the list. Eg, something like this:
$(".calculation-item").each(function(index) {
var my_cost = base_price + $(this).data("price");
var difference = Math.round(my_cost - base_cost);
});
I've created a working jsFiddle for you here: http://jsfiddle.net/HpEJf/6/. You'll need to implement decimal rounding etc but this should put you on the right track :)
If my understanding is correct, you want to display the cost difference from the previously selected radio button and the currently selected radio button.
To do that you need to keep track of the previously selected button. The only way I know of to do that is to set a variable outside the clickhandler scope to keep track of it and update the element in the clickhandler.
The rest is fairly straightforward. I updated your jsFiddle with an example of how to do it. The relevant code is below:
Adding at top of script:
//global for last checked/selected radio
var lastSelection = $(".calculation-item:checked");
//clear existing price diffs set by markup
$('span.processor_price').text('');
Added another function:
function priceDifference(oldPrice, newPrice) {
var difference = {
'cssClass': '',
'inCost': '0'
};
var fixedDiff = '';
var diff = newPrice - oldPrice;
diff = Math.ceil(Math.abs(diff * 100)) / 100;
fixedDiff = diff.toString();
if (newPrice < oldPrice) {
difference.cssClass = 'negative';
difference.inCost = '-' + fixedDiff;
} else if (newPrice > oldPrice) {
difference.cssClass = 'positive';
difference.inCost = '+' + fixedDiff;
}
/* else {
* must be the same, no reason for this block
* as the default empty string will suffice
* as will the cost difference of 0
}*/
return difference;
}
And changed your click handler to:
$(".calculation-item").click(function() {
var difference = {};
if (lastSelection) {
//get difference
difference = priceDifference($(lastSelection).data("price"), $(this).data("price"));
//change class
$(this).siblings('span.processor_price').addClass(difference.cssClass).text(difference.inCost);
$(lastSelection).siblings('span.processor_price').removeClass('positive').removeClass('negative').text('');
if (lastSelection !== this) {
lastSelection = this;
}
} else {
lastSelection = this;
}
CalculatePrice();
});