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
Related
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">
I've searched the questions here about 'how to enable my disabled button' but the one with the 'removeAttribute' simply does not work, don't know why.
I have this problem - once I reach 0 with my decrementing button it goes disabled so the user can't decrement to negative number but the problem is when I use the increment button the decrement one stays disabled, why ? I will be very greatfull if you guys tell me another way to solve this task. The point is I am now allowed to decrement below 0.
Here are my HTML and JS:
var value = 1;
var plus = document.getElementById('plus');
var minus = document.getElementById('minus');
function add() {
value++;
document.getElementById('num').innerHTML = value;
}
function take() {
value--;
document.getElementById('num').innerHTML = value;
if (value == 0) {
minus.disabled = true;
} else {
minus.disabled = false;
}
}
<input type="button" value="ADD" id="plus" onclick="add();">
<input type="button" value="TAKE" id="minus" onclick="take();">
<span id="num">1</span>
Because you do not run the logic when you click on the add button. You only do it on the minus button.
I would break it out into it own function
var value = 1;
var plus = document.getElementById('plus');
var minus = document.getElementById('minus');
function add() {
value++;
document.getElementById('num').innerHTML = value;
setBtnStates();
}
function take() {
value--;
document.getElementById('num').innerHTML = value;
setBtnStates();
}
function setBtnStates() {
if (value == 0) {
minus.disabled = true;
} else {
minus.disabled = false;
}
}
<input type="button" value="ADD" id="plus" onclick="add();">
<input type="button" value="TAKE" id="minus" onclick="take();">
<span id="num">1</span>
The statement can be simplified to
function setBtnStates() {
minus.disabled = value == 0;
}
I am building a website and I want to do calculations based on information provided. I obviously need to have information provided in two out of the three fields to calculate the third's value.
The three fields are:
Price Per Gallon
Gallons Bought
Total Sale
I obviously know that I can calculate the amount of gas bought by dividing the Total Sale amount by the Price Per Gallon.
However I want to calculate based on whatever two fields are entered. I am trying to find out the best way to do this.
I know this much:
Check to see which fields are empty
Determine which type of calculation to make
Here is what I have so far:
<form>
<input type="number" id="totalSale" placeholder="Total Sale Amount" class="calculate" />
<input type="number" id="gallonPrice" placeholder="Price Per Gallon" class="calculate" />
<input type="number" id="gallons" placeholder="Gallons" class="calculate" />
</form>
<script>
var e = document.getElementsByClassName("calculate");
function calc(){
var sale_amt = document.getElementById("totalSale");
var ppg = document.getElementById("gallonPrice");
var gallons = document.getElementById("gallons");
if (sale_amt || ppg !== null) {
var calc_gallons = sale_amt.value / ppg.value;
gallons.value = calc_gallons.toFixed(3);
}
}
for (var i = 0; i < e.length; i++) {
e[i].addEventListener('keyup', calc, false);
}
</script>
the logic should take into consideration which element is currently being entered (that will be this in calc). Also, you need to take into consideration what happens when all three have values, and you change one ... which of the other two should be changed?
See if this works for you
var sale_amt = document.getElementById("totalSale");
var ppg = document.getElementById("gallonPrice");
var gallons = document.getElementById("gallons");
function calc(){
var els = [sale_amt, ppg, gallons];
var values = [sale_amt.value, ppg.value, gallons.value];
var disabledElement = els.find(e=>e.disabled);
var numValues = els.filter(e => e.value !== '' && !e.disabled).length;
var calc_gallons = function() {
gallons.value = (values[0] / values[1]).toFixed(3);
};
var calc_ppg = function() {
ppg.value = (values[0] / values[2]).toFixed(3);
};
var calc_sale = function() {
sale_amt.value = (values[1] * values[2]).toFixed(2);
};
if (numValues < 3) {
if (numValues == 1 && disabledElement) {
disabledElement.disabled = false;
disabledElement.value = '';
disabledElement = null;
}
els.forEach(e => e.disabled = e == disabledElement || (numValues == 2 && e.value === ''));
}
disabledElement = els.find(e=>e.disabled);
switch((disabledElement && disabledElement.id) || '') {
case 'totalSale':
calc_sale();
break;
case 'gallonPrice':
calc_ppg();
break;
case 'gallons':
calc_gallons();
break;
}
}
var e = document.getElementsByClassName("calculate");
for (var i = 0; i < e.length; i++) {
e[i].addEventListener('keyup', calc, false);
e[i].addEventListener('change', calc, false);
}
I am trying to call a function in this javascript code. My code needs to check for whether the user selects var num, var letters and var symbols to be true or false. In the code, I preset the values but I still search the object choices for the variables that are true and push it into the array choices_made. However, since I need to randomly choose the order in which the num, letters and symbols appear, I randomly choose the class based on the Math.random(). However, it doesn't show me the alert(jumbled_result) afterwards.
http://jsfiddle.net/bdaxtv2g/1/
HTML
<input id="num" type="text" placeholder="Enter desired length">
<br/><br/>
<input id="press" type="button" value="jumble it up">
JS
$(document).ready(function(){
var fns={};
$('#press').click(function(){
var length = parseInt($('#num').val());
var num = true;
var letters = true;
var symbols = false;
gen(length, num, letters, symbols);
});
function gen(len, num, letters, sym){
var choices = {
1:num,
2:letters,
3:sym
};
var choice_made = ['0'];
var choice = 0;
var jumbled_result = '';
for(x in choices){
if(choices[x]==true){
choice_made.push(x);
}
}
for(i=0;i<len;i++){
var funName = 'choice';
choice = Math.round(Math.random() * (choice_made.length-1));
funName += choice_made[choice];
jumbled_result = fns[funName](jumbled_result);
}
alert(jumbled_result);
}
fns.choice0 = function choice0(jumbled_result){
var numbers = '0123456789';
return jumbled_result += numbers.charAt(Math.round(Math.random() * numbers.length));
}
fns.choice1 = function choice1(jumbled_result) {
var alpha = 'abcdefghijklmnopqrstuvwxyz';
return jumbled_result += alpha.charAt(Math.round(Math.random() * alpha.length));
}
});
You never declare functions within document.ready of jQuery. The functions should be declared during the first run(unless in special cases).
Here is a working code made out of your code. What I have done is just removed your functions out of document.ready event.
$(document).ready(function() {
$('#press').click(function() {
var length = parseInt($('#num').val());
var num = true;
var letters = true;
var symbols = false;
gen(length, num, letters, symbols);
});
});
var fns = {};
function gen(len, num, letters, sym) {
var choices = {
1: num,
2: letters,
3: sym
};
var choice_made = ['0'];
var choice = 0;
var jumbled_result = '';
for (x in choices) {
if (choices[x] == true) {
choice_made.push(x);
}
}
for (i = 0; i < len; i++) {
var funName = 'choice';
choice = Math.round(Math.random() * (choice_made.length - 1));
funName += choice_made[choice];
jumbled_result = fns[funName](jumbled_result);
}
alert(jumbled_result);
}
fns.choice0 = function choice0(jumbled_result) {
var numbers = '0123456789';
return jumbled_result += numbers.charAt(Math.round(Math.random() * numbers.length));
}
fns.choice1 = function choice1(jumbled_result) {
var alpha = 'abcdefghijklmnopqrstuvwxyz';
return jumbled_result += alpha.charAt(Math.round(Math.random() * alpha.length));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="num" type="text" placeholder="Enter desired length">
<br/>
<br/>
<input id="press" type="button" value="jumble it up">
Its because of the way the object choices have been intitialized.. Try this..
var choices = {
0:num,
1:letters,
2:sym
};
And also
var choice_made = [];
JS fiddle link : http://jsfiddle.net/8dw7nvr7/2/
I am looking for way to automate this selection.
For example, I will have 10 double inputs (20 inputs total) and I don't want to write JS script for each inputs, but simply use each() function (I am open to different ways) and declare only selectors.
JsFiddle: http://jsfiddle.net/vs7fa/
Idea:
var SELECTORS_H = array();
$.each(SELECTORS_H){
$('SELECTOR_H').keyup(function () {
// do magic
$('SELECTOR_V').val(num);
});
$('SELECTOR_V').keyup(function () {
// do magic
$('SELECTOR_H').val(num);
});
}
HTML:
<label for="h_one">H_ONE:</label>
<input type="text" name="h_one">
<label for="v_one">V_ONE:</label>
<input type="text" name="v_one">
There will be more of inputs. Pattern is:
h_one, v_one
h_two, v_two
h_something, v_something
...
JS:
$(function() {
$('input[name="h_one"]').keyup(function() {
var one = $(this).val();
if (one > 0) {
var num = Math.abs(one) * -1;
}
else {
var num = Math.abs(one) * 1;
}
$('input[name="v_one"]').val(num);
});
$('input[name="v_one"]').keyup(function() {
var two = $(this).val();
if (two > 0) {
var num = Math.abs(two) * -1;
}
else {
var num = Math.abs(two) * 1;
}
$('input[name="h_one"]').val(num);
});
});
You can handle this using a selector with a common class for all your element and data-attributes to know the element and the linked elements.
HTML:
<label>H_ONE:</label>
<input type="text" class="handler" data-id="h1" data-link="v1" />
<br>
<label>V_ONE:</label>
<input type="text" class="handler" data-id="v1" data-link="h1" />
Code:
$(function () {
$('.handler').keyup(function () {
var one = $(this).val();
if (one > 0) {
var num = Math.abs(one) * -1;
} else {
var num = Math.abs(one) * 1;
}
$('input[data-id=' + $(this).attr("data-link")+']').val(num);
});
});
Demo: http://jsfiddle.net/8KgTk/
may be this...
Jsfiddle: http://jsfiddle.net/vs7fa/3/
$('input[name="h_one"]').keyup(function () {
var num = DoMagic($(this));
$('input[name="v_one"]').val(num);
});
$('input[name="v_one"]').keyup(function () {
var num = DoMagic($(this));
$('input[name="h_one"]').val(num);
});
function DoMagic(element) {
var one = $(element).val();
if (one > 0) {
var num = Math.abs(one) * -1;
} else {
var num = Math.abs(one) * 1;
}
return num;
}
You should be able to perform the .each function by using jQuery and making the items the same class.
such as:
<label class="forElement" for="h_one">H_ONE:</label>
<input class="inputElement" type="text" name="h_one">
<label class="forElement"for="v_one">V_ONE:</label>
<input class="inputElement" type="text" name="v_one">
$('.forElement').each( function() {
//some code
}
You can do this without adding extra attributes if you want.
$(function () {
$('input[name^="h_"], input[name^="v_"]').keyup(function () {
var one = $(this).val();
var num = - one;
var inputType = $(this).attr("name").substr(0,1);
var inputNumber = $(this).attr("name").substr(2);
$('input[name="'+(inputType == 'v' ? 'h' : 'v')+'_' + inputNumber + '"]').val(num);
});
});
However Irvin Dominin aka Edward's solution is quite good.
Here's a sollution that doesn't require extra markup, and doesn't use string concatenation for logic. It uses $.proxy() to get correct scoping.
Fiddle