I have some code that I've implemented as a counter, however, can this code be slightly modified to allow a button to increase a value by 200 and then decrease down to 0? I understand that ++x will increase, but I'm not sure why +x won't add? Is it something to do with strings?
Javascript:
let x = 200;
$('.counter-button.counter-up').on('click', () => {
$('.counter-input.w-input').val( +x );
});
$('.counter-button.counter-down').on('click', () => {
if (x > 0) {
$('.counter-input.w-input').val( -x );
}
});
$('.counter-input.w-input').change(function () {
const num = Number($(this).val());
// if it's a number
if (num) {
// assign its value to x
x = num;
}
});
Thanks for any help with this!
For the record (honoring your initial question): here's a 'vanilla' solution.
{
document.addEventListener("click", addOrSubtract);
function addOrSubtract(evt) {
const from = evt.target;
if (from.dataset.addvalue) {
const numberInput = document.querySelector("input");
const newValue = +numberInput.value + +from.dataset.addvalue;
numberInput.value = newValue >= +numberInput.min
&& newValue <= +numberInput.max ? newValue : numberInput.value;
}
}
}
<input type="number" min="0" max="4000" value="0" readonly>
<button data-addvalue="200">increment</button> (max 4000)
<button data-addvalue="-200">decrement</button> (min 0)
.val() doesn't increase or decrease, it assigns. Try:
$('.counter-input.w-input').val( $('.counter-input.w-input').val() + x );
When you pass +x or -x it will just set that value as a value of the input. So you could first calculate the new value by adding or subtracting x of the current value based on the clicked button class.
let x = 200;
let input = document.querySelector('.counter-input.w-input')
let buttons = document.querySelectorAll('.counter-button')
buttons.forEach(b => {
b.addEventListener('click', function() {
let value = +input.value;
if (this.classList.contains('counter-up')) {
value += x
} else if (value > 0) {
value -= x
}
input.value = value
})
})
<button class="counter-button counter-up">Up</button>
<button class="counter-button counter-down">Down</button>
<input value="0" type="text" class="counter-input w-input">
Related
I am trying to evaluate when the user inputs nothing (an empty string) or anything besides a number (Not a number). After I console log the an input of empty string a NaN is returned. I am not sure why the else-if statement is never recognized if I test for both an empty string or NaN value. This also ultimately affects my average total score.
const equationTag = document.querySelector('div#equation');
const inputBtn = document.querySelector('input.submit-btn');
const incorrectTag = document.querySelector('p#incorrect');
const correctTag = document.querySelector('p#correct');
const counterTag = document.querySelector('div#counter');
const exitButton = document.querySelector('button.exit-btn');
const displayButton = document.querySelector('button.display-btn');
const resultModal = document.querySelector('section.stats-section');
const averageP = document.querySelector('p.avg');
const guessP = document.querySelector('p.total-guesses');
let points = 0;
let correctGuesses = 0;
let incorrectGuess = 0;
let totalGuesses = 0;
/*
Takes a min and max value as parameters, and
returns a randomized integer
*/
function getRandomValue(min, max) {
let r = Math.floor(Math.random() * (max - min + 1)) + min;
return r;
}
// Displays multiplcation equation on the user interface
function displayEquation() {
equationTag.textContent = `${integerOne} x ${integerTwo}=`;
}
// Returns the product of the two integers
function getProduct() {
return integerOne * integerTwo;
}
/*
Event listener grabs user input on click
and clears user input afterwards
*/
inputBtn.addEventListener('click', () => {
const inputTag = document.querySelector('#num');
const answer = parseFloat(inputTag.value);
evaluateAnswer(answer);
inputTag.value = "";
inputTag.focus();
})
/*
Event listener grabs user input on enter key
and clears user input afterwards
*/
document.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
const inputTag = document.querySelector('#num');
const answer = parseFloat(inputTag.value);
evaluateAnswer(answer);
inputTag.value = "";
inputTag.focus();
}
})
exitButton.addEventListener('click', () => {
setDisplayNone(resultModal);
})
displayButton.addEventListener('click', () => {
setDisplayBlock(resultModal);
})
/*
Takes a integer user input as an argument
and compares whether the answer is correct or not.
*/
function evaluateAnswer(input) {
console.log('Input value on eval ', input); // double checking value
if (input !== getProduct()) {
subtractPoint();
incorrectGuess++;
} else if (input === ' ' || isNaN()) { // I am not sure why it's never evaluated
console.log('Input value is empty or not a number ', input);
} else {
addPoint();
correctGuesses++;
}
totalGuesses++;
restartGame();
guessP.textContent = "Incorrect Guesses= " + incorrectGuess;
let average = (correctGuesses / totalGuesses);
let precisionAvg = roundToPrecision(average, 2);
averageP.textContent = `${(precisionAvg * 100).toFixed(2)}%`;
// console.log('Total guesses: ', totalGuesses);
// console.log('Incorrect ', incorrectGuess);
// console.log("Average: ", average)
}
/*
Evaluates if the points are less
than zero then restart points to 0
else minus a point.
*/
function subtractPoint() {
if (points <= 0) {
points = 0;
} else {
points -= 1;
}
setDisplayBlock(incorrectTag);
setDisplayNone(correctTag);
incorrectTag.textContent = ('Incorrect: ' + integerOne + ' x ' + integerTwo + ' = ' + getProduct());
setPoint();
}
// Sets new updated point
function setPoint() {
counterTag.textContent = points;
}
// Adds a point and updates earned points
function addPoint() {
points += 1;
correctTag.textContent = ('Correct!');
setDisplayBlock(correctTag);
setDisplayNone(incorrectTag);
setPoint();
}
/*
Resets game and gets two new random integers
and calls the displayEquation function.
*/
function restartGame() {
integerOne = getRandomValue(0, 12);
integerTwo = getRandomValue(0, 12);
displayEquation();
}
// sets css display block and opacity 1 on element
function setDisplayBlock(displayResult) {
displayResult.style.display = 'block';
displayResult.style.opacity = 1;
}
// sets css display none and opacity 0 on element
function setDisplayNone(displayResult) {
displayResult.style.display = 'none';
displayResult.style.opacity = 0;
}
/*
Takes a value as a parameter, and integer as a parameter
returns a rounded value with two decimal places at most
https://stackoverflow.com/questions/11832914/how-to-round-to-at-most-2-decimal-places-if-necessary/11832950#11832950
*/
function roundToPrecision(value, decimals = 2) {
const pow = Math.pow(10, decimals);
return Math.round((value + Number.EPSILON) * pow) / pow;
}
// run game on load
let integerOne = getRandomValue(0, 12);
let integerTwo = getRandomValue(0, 12);
displayEquation();
<body>
<header>
<h1 id="title">Multiply Me</h1>
</header>
<main>
<div id="equation"></div>
<div id="counter">0</div>
<input type="number" id="num" value="" title="input">
<input type="submit" class="submit-btn">
<button type="submit" class="display-btn" value="Show Results">+</button>
<div id="response">
<p id="correct"></p>
<p id="incorrect"></p>
</div>
<section class="stats-section">
<h3 class="h3-title">Overall Results:</h3>
<button class="exit-btn">x</button>
<article class="article-stats">
<p class="total-guesses"></p>
<p class="avg"></p>
</article>
</section>
</main>
</body>
Several issues apart from not using isNaN correctly
You cannot see if a value is a single space after parseFloating it.
I would suggest
const answer = inputTag.value;
evaluateAnswer(answer);
where you have this. Note the order and that I test the positive outcome before the negative
function evaluateAnswer(input) {
input = input.trim();
if (input === "" || isNaN(input)) {
console.log('Input value is empty or not a number ', input);
return; /* Any need to continue? */
} else if (input === getProduct()) {
addPoint();
correctGuesses++;
} else {
subtractPoint();
incorrectGuess++;
}
You must first check that the input value is not empty, so you must modify the order of the condition. And it is better to add a return to exit the function when no value is entered so that a new question is not generated.
function evaluateAnswer(input) {
console.log('Input value on eval ', input); // double checking value
if (input === '' || isNaN(input)) { // I am not sure why it's never evaluated
console.log('Input value is empty or not a number ', input);
return;
} else if (input !== getProduct()) {
subtractPoint();
incorrectGuess++;
} else{
addPoint();
correctGuesses++;
}
totalGuesses++;
restartGame();
guessP.textContent = "Incorrect Guesses= " + incorrectGuess;
let average = (correctGuesses / totalGuesses);
let precisionAvg = roundToPrecision(average, 2);
averageP.textContent = `${(precisionAvg * 100).toFixed(2)}%`;
}
I did a Slidebar (0-99) which is working well.
I want to add 2 buttons to manually change it (first button -1 ; second button +1).
It was working well with my "-1" code for the first button, but the second one isnt working and I dont understand why. (It add 1 but for example if my slidebar is at 50, when i click its not going to 51 but 501).
Here is my code :
<div>
<button id="moins1" onclick="moins1()">MOINS 1</button>
<span class="unselectable rangeValue1" id="rangeValue1">RR</span>
<Input class="range" type="range" name="BarreRR" value="0" min="0" max="99" onChange="rangeSlide1(this.value)" onmousemove="rangeSlide1(this.value)"></Input>
<button id="plus1" onclick="plus1()">PLUS 1</button>
</div>
<script type="text/javascript">
function rangeSlide1(value) {
document.getElementById('rangeValue1').innerHTML = value;
}
function moins1(){
var Yop = document.getElementById('rangeValue1').textContent;
Yop -=1;
document.getElementById('rangeValue1').innerHTML = Yop;
console.log(Yop);
}
function plus1(){
var Yop = document.getElementById('rangeValue1').textContent;
Yop +=1;
document.getElementById('rangeValue1').innerHTML = Yop;
console.log(Yop);
}
</script>
Thanks for help, Zartex.
The issue is that textContent returns string and using + operator will try to concatenate the values. So you can parse it. But I would recommend directly connecting your range with displayed value and only alter the range using the buttons or change them together for example:
function rangeSlide1(value) {
document.getElementById('rangeValue1').innerHTML = value;
}
function moins1() {
let range = document.querySelector('.range')
if (range.value != 0) {
let newValue = range.value - 1
document.getElementById('rangeValue1').innerHTML = newValue
range.value = newValue
}
}
function plus1() {
let range = document.querySelector('.range')
if (range.value < 99) {
let newValue = Number(range.value) + 1
document.getElementById('rangeValue1').innerHTML = newValue
range.value = newValue
}
}
<div>
<button id="moins1" onclick="moins1()">MOINS 1</button>
<span class="unselectable rangeValue1" id="rangeValue1">RR</span>
<Input class="range" type="range" name="BarreRR" value="0" min="0" max="99" onChange="rangeSlide1(this.value)" onmousemove="rangeSlide1(this.value)"></Input>
<button id="plus1" onclick="plus1()">PLUS 1</button>
</div>
Considering your range is limited from 0 to 100 I added condition not to go under 0
it will help you,
Yop value always in "50" + 1 it will return by concat 501
so parseInt your string and add/minus by 1
function moins1(){
var Yop = document.getElementById('rangeValue1').textContent;
Yop = parseInt(Yop)-1;
document.getElementById('rangeValue1').innerHTML = Yop;
console.log(Yop);
}
function plus1(){
var Yop = document.getElementById('rangeValue1').textContent;
Yop = parseInt(Yop)+1;
document.getElementById('rangeValue1').innerHTML = Yop;
console.log(Yop);
}
I'm trying to have a counter that can respond to input values and add it to displayed count but continue to count by 1. The count starts at 0. I have the counter working with buttons, but not with the added input.
let decreaseBtn = document.getElementById("buttonDecrease");
let increaseBtn = document.getElementById("buttonIncrease");
let counter = document.getElementById("counter");
let inputValue = document.getElementById("quantity").inputValue
let count = 0;
decreaseBtn.addEventListener("click", () => {
count--;
counter.innerHTML = count;
counterStyle();
});
increaseBtn.addEventListener("click", () => {
count++;
counter.innerHTML = count;
counterStyle();
});
function counterStyle() {
if (count < 0) {
counter.classList.add("negative");
} else if (count > 0) {
counter.classList.add("positive");
} else {
counter.classList.remove("negative");
counter.classList.remove("positive");
}
}
function addInput() {
console.log(inputValue)
}
addInput();
<h1 id="counter">0</h1>
<div id="button__wrapper">
<button id="buttonDecrease">-</button>
<input type="text" id="quantity" value="1">
<button id="buttonIncrease">+</button>
</div>
Yuo need to get the value of the input in your event listener functions, not when the script starts. Then use that instead of just incrementing and decrementing.
The property to get the value of an input is .value, not .inputValue.
let decreaseBtn = document.getElementById("buttonDecrease");
let increaseBtn = document.getElementById("buttonIncrease");
let counter = document.getElementById("counter");
let quantity = document.getElementById("quantity");
let count = 0;
decreaseBtn.addEventListener("click", () => {
count -= addInput();
counter.innerHTML = count;
counterStyle();
});
increaseBtn.addEventListener("click", () => {
count += addInput();
counter.innerHTML = count;
counterStyle();
});
function counterStyle() {
if (count < 0) {
counter.classList.add("negative");
counter.classList.remove("positive");
} else if (count > 0) {
counter.classList.add("positive");
counter.classList.remove("negative");
} else {
counter.classList.remove("negative");
counter.classList.remove("positive");
}
}
function addInput() {
return parseInt(quantity.value);
}
.positive {
background-color: green;
}
.negative {
background-color: red;
}
<h1 id="counter">0</h1>
<div id="button__wrapper">
<button id="buttonDecrease">-</button>
<input type="text" id="quantity" value="1">
<button id="buttonIncrease">+</button>
</div>
You have increment and decrement operators when you handle the click event. This is why it is always just adding or subtracting by 1, and not by the value of the input. You should be adding the value of the input element, after using parseInt() to make it into an add-able integer.
Your code that I'm changing:
count--;
What I'm changing it to...
count -= parseInt(document.getElementById('quantity').value, 10);
And I'm doing the same for count++.
In addition, it seems your counterStyles() function isn't removing classes appropriately, and sometimes you'll have a red background with positive integers. I fixed this up by adding the needed removeClass() calls here.
The rest of the code is the same...
let decreaseBtn = document.getElementById("buttonDecrease");
let increaseBtn = document.getElementById("buttonIncrease");
let counter = document.getElementById("counter");
let inputValue = document.getElementById("quantity").inputValue
let count = 0;
decreaseBtn.addEventListener("click", () => {
count -= parseInt(document.getElementById('quantity').value, 10);
counter.innerHTML = count;
counterStyle();
});
increaseBtn.addEventListener("click", () => {
count += parseInt(document.getElementById('quantity').value, 10);
counter.innerHTML = count;
counterStyle();
});
function counterStyle() {
if (count < 0) {
counter.classList.add("negative");
counter.classList.remove("positive");
} else if (count > 0) {
counter.classList.add("positive");
counter.classList.remove("negative");
} else {
counter.classList.remove("negative");
counter.classList.remove("positive");
}
}
function addInput() {
console.log(inputValue)
}
addInput();
.positive {
background-color: green;
}
.negative {
background-color: red;
}
<h1 id="counter">0</h1>
<div id="button__wrapper">
<button id="buttonDecrease">-</button>
<input type="text" id="quantity" value="1">
<button id="buttonIncrease">+</button>
</div>
I have an spinner element made from two spans for + and - and an text input element in the middle that shows the quantity selected from the increase and decrease:
<div class="quantity-spinner">
<span class="input-number-decrement">–</span><input class="input-number" type="text" value="1" min="0" max="10"><span class="input-number-increment">+</
</div>
I have two instances of this element, but currently when increasing the quantity for one of the elements it also controls the other one.
My question is, how can I separate the two elements, so that they are controller independently.
Here is my JavaScript:
(function() {
window.inputNumber = function(el) {
var min = el.attr('min') || false;
var max = el.attr('max') || false;
var els = {};
els.dec = el.prev();
els.inc = el.next();
el.each(function() {
init($(this));
});
function init(el) {
els.dec.on('click', decrement);
els.inc.on('click', increment);
function decrement() {
var value = el[0].value;
value--;
if(!min || value >= min) {
el[0].value = value;
}
}
function increment() {
var value = el[0].value;
value++;
if(!max || value <= max) {
el[0].value = value++;
}
}
}
};
})();
inputNumber($('.input-number'));
Thank you in advance!
try replacing
els.dec.on('click', decrement);
els.inc.on('click', increment);
by
el.prev().on('click', decrement);
el.next().on('click', increment);
you bug comes from the fact that els.dec and els.inc contain
predecessors and successors for both counters
Before anything you need to see the effect:
jsFiddle
As you can see it is a calculator where you can put a value anywhere and covert it to other values, but the problem is that i cant enter decimal int values like 0.3 or 0.999. What is the cause of this?
var id = {
mm: 1,
cm: 10,
m: 1000,
km: 1000000
};
$('input.bx').on('keyup', function() {
var t = $(this).val();
var i = id[$(this).attr("id")];
var v = parseInt(t, 10);
for (pp in id) {
if (t !== '') {
$("#" + pp).val(v / id[pp] * i);
} else {
$(".bx").val('');
}
}
});
<input type='text' class='bx' id='mm'> Milimeter<br>
<input type='text' class='bx' id='cm'> Centimeter<br>
<input type='text' class='bx' id='m'> Meter<br>
<input type='text' class='bx' id='km'> Kilometer<br>
parseInt is the "problem" since it returns integer - decimal values are not integer but floats. If you want that you must replace it with parseFloat.
1.First you need to use parseFloat because int cant have decimals.
2.Second i would use onChange.
http://jsfiddle.net/Kfkjy/10/
a working fiddle here
you have to use parseFloat and dont try to set the current focused element value cause you are over riding it while typing.
this example is working fine
http://jsfiddle.net/Mohamed_aboelenen/D6T7j/1/
$('input.bx').on('keyup', function() {
var t = $(this).val();
var i = id[$(this).attr("id")];
var v = parseFloat(t, 10);
var a = $(this).attr("id"); // the textbox you write in
for (pp in id) {
if (t !== '' ) {
if(a != pp){ // make changes to any textbox except the one you write in
$("#" + pp).val(v / id[pp] * i);
}
} else {
$(".bx").val('');
}
}
});
$('input.bx').on('blur', function() {
var t = $(this).val();
var i = id[$(this).attr("id")];
var v = Number(t, 10);
for (pp in id) {
if (t !== '') {
$("#" + pp).val(parseFloat(v / id[pp] * i));
} else {
$(".bx").val('');
}
}
});