Is there a way that i can connect inputs together? - javascript

I have 3 input fields that I would like to connect/link to each other. I want them to have a total value limited to 100%. So if 1 input is 40% then the other 2 input have 60% left to distribute in their value.
I am trying to find my answer on google, but i think I am searching with the wrong criteria. Does somebody know how to do this or have a guide on how to do it?
<div class="form_groep">
<label class="input_label_koolhydraten"><b>Koolhydraten</b></label>
<input class="input_macro_koolhydraten" type="number" name="message" id="macro_koolhyrdaten" required><span>%</span>
</div>
<div class="form_groep">
<label class="input_label_eiwitten"><b>Eiwitten</b></label>
<input class="input_macro_eiwitten" type="number" name="message" id="macro_eiwitten" required><span>%</span>
</div>
<div class="form_groep">
<label class="input_label_vetten"><b>Vetten</b></label>
<input class="input_macro_vetten" type="number" name="message" id="macro_vetten" required><span>%</span><br><br>
</div>

If I understood correctly, you want to have 3 inputs that the sum of its values do not exceeds 100, right?
If yes, so my code below can help you. There you will get all inputs in an array, then add a listener to the change of each one. This Listener will get the value of the input that is being changed and check if its value summed with the value of ther others don't exceed 100.
Check the code and if you didn't understand something, tell in the comments.
Also, warn me if I understood you wrong.
let total = 0;
const ipts = Array.from(document.getElementsByTagName('input'));
const totalElem = document.getElementById("total")
for (var i = 0; i < ipts.length; i++){
ipts[i].onchange = countTotal
}
function countTotal(){
let value = parseFloat(this.value);
total = ipts.reduce((counter,elem) => parseFloat(elem.value) + counter, 0);
total -= value;
if (value > 100){
this.value = 100;
}
if (value + total > 100){
this.value = 100 - total;
}
totalElem.innerText = total + parseFloat(this.value);
}
<div class="form_groep">
<label class="input_label_koolhydraten"><b>Koolhydraten</b></label>
<input class="input_macro_koolhydraten" type="number" name="message" id="macro_koolhyrdaten" required value='0'><span>%</span>
</div>
<div class="form_groep">
<label class="input_label_eiwitten"><b>Eiwitten</b></label>
<input class="input_macro_eiwitten" type="number" name="message" id="macro_eiwitten" required value='0'><span>%</span>
</div>
<div class="form_groep">
<label class="input_label_vetten"><b>Vetten</b></label>
<input class="input_macro_vetten" type="number" name="message" id="macro_vetten" required value='0'><span>%</span><br><br>
</div>
<div><span id="total">0</span> out of 100% </div>

You could listen to change or input events from all of those inputs in js, and then get values from all, count their lengths and if sum_of_their_lengths > some_maximum_value then block them.

Related

Checkbox not working on checked to add values

I have created calculation system project with javascripts all things are good calculation done perfectly tax include perfectly but tax not included when I click on checkebox, it add when I type something in input field, I want values changes on when I clicked on checkbox and even when I type something
html
<div class="form-group row">
<div class="col-sm-6">
<input type="float" class="form-control form-control-user" id="BMS_qty" name="BMS_qty" placeholder="BMS Quantity">
<input type="float" class="form-control form-control-user" id="BMS_price" name="BMS_price" placeholder="BMS Price">
</div>
</div>
<div class="col-sm-6 form-check">
<input type="checkbox" id="tax" name="taxamount" value="0.17">
<label for="tax">Included Tax</label><br>
<label for="total_expenses1" style="text-align: right;">Total:- </label>
<span id="total_expenses1"></span>
</div>
javascript
$('input').keyup(function(){ // run anytime the value changes
var BMS_qty = Number($('#BMS_qty').val());
var BMS_price = Number($('#BMS_price').val());
if(document.getElementById("tax").checked) {
var tax = 0.17;
} else {
tax = 0;
}
var subtotal = BMS_qty * BMS_price;
var total = tax * subtotal;
$('#total_expenses1').html(total + subtotal); // add them and output it
// add them and output it
});
The problem is that the keyup() method will only act on an <input type="checkbox"> when the space key is pressed to activate it.
To avoid this kind of problem I'd suggest switching the code to react to input events (which covers any event in which the value/state of an <input> is changed).
One approach to solving the problem is below, with explanatory comments included:
// we select all <input> elements regardless of their type attribute,
// and bind the anonymous function of the on() method as the event-handler
// for the 'input' event:
$('input').on('input', function() {
// switching to the use of const to declare variables that shouldn't
// change after they've been defined, and we use parseInt() instead
// of Number() to convert those the entered-values into numbers
// supplying the radix (base) argument of 10 because we're working
// with base-10 numbers (this is largely a personal preference, I
// don't think there's a particular argument for, or against, this
// change):
const BMS_qty = parseInt($('#BMS_qty').val(), 10),
BMS_price = parseFloat($('#BMS_price').val()),
// here we use a conditional (ternary) operator, in which we
// assess - using the .is() method - whether the element with
// the id of "tax" is checked.
// If it is checked the value of tax is 0.17, if it is not
// the value is 0:
tax = $('#tax').is(':checked') ? 0.17 : 0;
// using let to declare variables that may need to change if
// the calculations/results need to be modified in production:
let subtotal = BMS_qty * BMS_price,
total = tax * subtotal;
// adding the values, andd writing it the element with an
// id equal to "total_expenses", though I've switched to using
// the text() method to avoid accidentally trying to insert any
// HTML elements in the future:
$('#total_expenses1').text(total + subtotal);
});
<div class="form-group row">
<div class="col-sm-6">
<input type="float" class="form-control form-control-user" id="BMS_qty" name="BMS_qty" placeholder="BMS Quantity">
<input type="float" class="form-control form-control-user" id="BMS_price" name="BMS_price" placeholder="BMS Price">
</div>
</div>
<div class="col-sm-6 form-check">
<input type="checkbox" id="tax" name="taxamount" value="0.17">
<label for="tax">Included Tax</label><br>
<label for="total_expenses1" style="text-align: right;">Total:- </label>
<span id="total_expenses1"></span>
</div>
JS Fiddle demo.
References:
JavaScript:
Conditional ("ternary") Operator.
parseFloat().
parseInt().
jQuery:
is().
on().
text().
You need to use on() to get events you need
I think, you also need to change Number() by parseInt()
$(document).on('keyup keypress keydown change', 'input[name="BMS_qty"], input[name="BMS_price"], input[name="taxamount"]', function(){ // or keypress I have the same result
var BMS_qty = parseInt($('#BMS_qty').val());
var BMS_price = parseInt($('#BMS_price').val());
if(document.getElementById("tax").checked) {
var tax = 0.17;
} else {
tax = 0;
}
var subtotal = BMS_qty * BMS_price;
var total = tax * subtotal;
$('#total_expenses1').html(total + subtotal); // add them and output it
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-group row">
<div class="col-sm-6">
<input type="float" class="form-control form-control-user" id="BMS_qty" name="BMS_qty" placeholder="BMS Quantity">
<input type="float" class="form-control form-control-user" id="BMS_price" name="BMS_price" placeholder="BMS Price">
</div>
</div>
<div class="col-sm-6 form-check">
<input type="checkbox" id="tax" name="taxamount" value="0.17">
<label for="tax">Included Tax</label><br>
<label for="total_expenses1" style="text-align: right;">Total:- </label>
<span id="total_expenses1">0</span>
</div>

using parseFloat returns user input as strings added together in JavaScript

I'm writing a budget calculator and the issue that I'm having is parsing the user input. For testing purposes, I was using parseInt() and that would add the totals just fine, but changing to parseFloat() autopopulates the "total" form with the user input added together as strings. The commented out line in the if-statement for isNaN is what I had tried before, and both simply return LiquidTotal as strings added all together.
What I want is to allow multiple numeric user inputs, such as 10 and 10.50, and for the total to display as $20.50, but right now it displays as $1010.50
var LiquidTotal;
function LiquidMath()
{
var a = document.getElementById("cash").value;
var b = document.getElementById("checkings").value;
var c = document.getElementById("savings").value;
var d = document.getElementById("market").value;
var e = document.getElementById("LCD").value;
var f = document.getElementById("LiquidOther1").value;
var g = document.getElementById("LiquidOther2").value;
var h = document.getElementById("LiquidOther3").value;
parseFloat(a).toFixed(2);
parseFloat(b).toFixed(2);
parseFloat(c).toFixed(2);
parseFloat(d).toFixed(2);
parseFloat(e).toFixed(2);
parseFloat(f).toFixed(2);
parseFloat(g).toFixed(2);
parseFloat(h).toFixed(2);
LiquidTotal = a + b + c + d + e + f + g + h;
if (isNaN(LiquidTotal))
{
return false;
}
else
{
//document.getElementById("DisplayLiquidTotal").value = LiquidTotal;
document.getElementById("DisplayLiquidTotal").value = '$' + parseFloat(LiquidTotal).toFixed(2);
}
return document.getElementById("LiquidTotal").value;
}
Here is my HTML for this field, in case I messed anything up there as well.
<h4>Liquid Assets</h4>
<div class="row" style="padding:1px;">
<div class="col-xs-8">Cash On Hand: <input type="text" id="cash" onblur="LiquidMath()" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
<div class="col-xs-8">Checking Account: <input type="text" id="checkings" onblur="LiquidMath()" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
<div class="col-xs-8">Savings Account: <input type="text" id="savings" onblur="LiquidMath()" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
<div class="col-xs-8">Money Market Fund: <input type="text" id="market" onblur="LiquidMath()" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
<div class="col-xs-8">CD Less Than One Year: <input type="text" id="LCD" onblur="LiquidMath()" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
<div class="col-xs-8">Other: <input type="number" id="LiquidOther1" onblur="LiquidMath()" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
<div class="col-xs-8">Other: <input type="number" id="LiquidOther2" onblur="LiquidMath()" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
<div class="col-xs-8">Other: <input type="number" id="LiquidOther3" onblur="LiquidMath()" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
<div class="col-xs-8">Total: <input type="text" id="DisplayLiquidTotal" onblur="LiquidMath()" readonly="readonly" class="form-control" maxlength="30" style="background-color: #FFFFE0;"/></div>
You have multiple problems.
parseFloat and toFixed both return new values, they don't mutate the inputs.
While parseFloat returns a float, toFixed converts number types and returns a string. So you'll still have a string if you keep toFixed.
Strings are not added with arithmetic, adding strings in Javascript results in concatenation.
If you want to add numbers together, you need to assign the return value of parseFloat and stop using toFixed.
The problem you're having is that parseFloat returns a value. It doesn't alter a value in place.
This is what you want:
a = parseFloat(a).toFixed(2);
b = parseFloat(b).toFixed(2);
... and so on.
Your fundamental issue lies, as mentioned by other answers, in parseFloat not altering the variable that it is passed.
It seems to me as though you are also being overzealous with rounding decimal places when I presume you only really need to do that right at the end when you want to display the result of the sum. I'd also suggest tidying things up by encapsulating the repeated behaviour into helper functions, so something like:
// Get an element by ID and convert it to a float
const getFloatById = element => {
return parseFloat(document.getElementById(element));
}
const elementsToSum = ['cash', 'checkings', 'savings', 'market', 'LCD', 'LiquidOther1', 'LiquidOther2', 'LiquidOther3'];
// Iterate over the list of element names
LiquidTotal = elementsToSum.map(el => getFloatById(el))
// use reduce to sum all elements
.reduce((accum, current) => {
return accum + current
}, 0)
// then convert to a 2 decimal place string
.toFixed(2);

Toggle field depending on value

$(document).ready(function () {
toggleFields();
});
function toggleFields() {
if ($("#people").val() == 1)
$("#personen1").show();
else
$("#personen1").hide();
$("#personen2").hide();
$("#personen3").hide();
$("#personen4").hide();
$("#personen5").hide();
$("#personen6").hide();
$("#personen7").hide();
$("#personen8").hide();
}
<p>Personen:
<input type="number" id="people" name="ppl" min="1" class="uniform-input number" value="1" required="">
</p>
<div id="personen1">
<p>1. Person:
<input id="personen1_person1" type="text" name="person_name" />
</p>
</div>
<div id="personen2">
<p>1. Person:
<input id="personen2_person1" type="text" name="person_name" />
</p>
<p>2. Person:
<input id="personen2_person2" type="text" name="person2_name" />
</p>
</div>
<div id="personen3">
<p>1. Person:
<input id="personen3_person1" type="text" name="person_name" />
</p>
<p>2. Person:
<input id="personen3_person2" type="text" name="person2_name" />
</p>
<p>3. Person:
<input id="personen3_person3" type="text" name="person3_name" />
</p>
</div>
I have a people number input on my landingpage. I want to use the input value to add fields to my checkout. Like if the input is 5 I want 5 fields in my checkout page so the customer can fill in the names. The code above is not working correctly. What am I missing?
The first and foremost mistake you are making is duplicating ids, which are supposed to be unique, else unintended effects may appear.
The next thing is, the snippet will not work because you haven't included jQuery library, which is more important than anything to execute the $ function.
Thirdly, find these mistakes you have made:
You didn't bind the event with the input.
You need to check the input for the existence of id.
You aren't closing the if correctly.
You can compress the code a lot of effective ways, by using class or by using ids in a single $ selector.
$(document).ready(function () {
toggleFields();
$("#people").on("keyup change", function () {
toggleFields();
});
});
function toggleFields() {
$("#personen1, #personen2, #personen3, #personen4, #personen5, #personen6, #personen7, #personen8").hide();
if ($("#people").val() < 9)
$("#personen" + $("#people").val()).show();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p>Personen:
<input type="number" id="people" name="ppl" min="1" class="uniform-input number" value="1" required="">
</p>
<div id="personen1">
<p>1. Person:
<input id="person1-1" type="text" name="person_name" />
</p>
</div>
<div id="personen2">
<p>1. Person:
<input id="person2-1" type="text" name="person_name" />
</p>
<p>2. Person:
<input id="person2-2" type="text" name="person2_name" />
</p>
</div>
<div id="personen3">
<p>1. Person:
<input id="person3-1" type="text" name="person_name" />
</p>
<p>2. Person:
<input id="person3-2" type="text" name="person2_name" />
</p>
<p>3. Person:
<input id="person3-3" type="text" name="person3_name" />
</p>
</div>
You should not have multiple ids with same value.
That is not a right way of doing this, you should generate the HTML using JavaScript only:
// Sample code, you can create a function for this as well.
$(function(){
var count = 5; // Change this count with the input field value.
var _html = "";
for(var i=0; i<count; i++){
_html += '<p>'+(i+1)+'. Person:'
+'<input id="person'+(i+1)+'" type="text" name="person'+(i+1)+'_name" />'
+'</p>';
}
$(".container").html(_html);
});
Here is a fiddle
Every id attribute you use on a webpage has to be unique in the entire document, also -- you're using some kind of template to load when a user types a number but what if a user wants to add 10 people instead of 3 or 5? Individually adding cases will cause you much pain in the future.
I also understand that you want users to input a number and then get a certain amount of fields back from that, with that assumption made the code
$(document).ready(function() {
toggleFields();
});
will not work since it only gets executed once, onload of the page and doesn't get executed anymore after that since no events are bound.
var insertPeople = function(n) {
var amt = !isNaN(n) ? n : 1;
var fieldStr = '';
//using a for loop to 'build' the fields dynamically
for (var i = 0; i < amt; i++) {
var num = i + 1;
fieldStr += '<p>'+ num +'. person<input type="text" id="person'+ num +'" name="person'+ num +'_name"></p>'
}
//append HTML to container
$('#people-container').html(fieldStr);
}
//Use this to insert fields on page load instantly.
$(insertPeople);
//Use this if you would like a user to control the amount of fields through an input field.
$(function() { //shorthand for $(document).ready
$('#people').on('keyup', function() {
insertPeople($(this).val());
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="number" id="people" value="1" />
<div id="people-container"></div>
This code will loop for n times where n is the user input (validate the type of that yourself) and creates fields with ID's starting from 0 through the end point at the end of the loop. At the last step it appends the fields to a container, if this were a form then that form would simply be submit with those values.

associate number in number field with the number of newly created js div's

I have a set of number input fields, labeled small & medium.., and a set of div's with the label small and medium. When you add a number to the small number input field a text input insertsAfter the div labeled small. When you subtract a number from the small number input field, the text input field that was recently added is removed. the adding and removing of the text input is be the last one in the list. This same thing goes for the medium number field and medium label/textfield
please see JSFiddle for reference
http://jsfiddle.net/7PhJZ/53/
Right now my script is working correctly when I click the up or down buttons on the number field. But When I type in, for instance 5 in the small number field, only one new div/name input fields appears under the label small. I need the adding and subtracting of these input fields to be generated when I use the arrows and when I type in a number. So when I type in "5" 5 name/text input fields should appear under the associated label.
html :
<div id="product-1">
<div class="size-field">
<div id="size-label">s</div>
<div class="number-input">
<input id="Small" class="product-quantity" type="number" name="Small"
min="0" max="9999" data-product-id="1"></input>
</div>
</div>
<div id="size-label">m</div>
<div class="number-input">
<input id="Medium" class="product-quantity" type="number"
name="Medium" min="0" max="9999" data-product-id="1"></input>
</div>
<div class="name-number-header">
<h5>HEADER<h5></div>
<div class="name-number-field-container" data-size="Small">small:
</div>
<div class="name-number-field-container" data-size="Medium">medium:
</div>
</div>
<br clear="all">
<div id="product-2">
<div class="size-field">
<div id="size-label">s</div>
<div class="number-input">
<input id="Small" class="product-quantity" type="number" name="Small"
min="0" max="9999" data-product-id="2"></input>
</div>
</div>
<div id="size-label">m</div>
<div class="number-input">
<input id="Medium" class="product-quantity" type="number" name="Medium"
min="0" max="9999" data-product-id="2"></input>
</div>
<br clear="all">
<div class="name-number-header"><h5>HEADER<h5></div>
<div class="name-number-field-container" data-size="Small">small:
</div>
<div class="name-number-field-container" data-size="Medium">medium:
</div>
</div>
js :
$('.product-quantity').each(function () {
$(this).data('val', this.value);
}).on('change', function () {
var val = $(this).val(),
old = $(this).data('val'),
input = $('<div/>', {'class': 'name-number-field'}).html('<input
class="name-field" name="name" placeholder="Name" type="text">'),
ele = $(this).closest('[id^="product"]').find('[data-size="' + this.name + '"]'),
inc = val >= old;
if (inc) {
$(input).insertAfter(ele.nextUntil(':not(.name-number-field)').last()
.length ? ele.nextUntil(':not(.name-number-field)').last() : ele);
} else {
ele.nextUntil(':not(.name-number-field)').last().remove();
}
$(this).data('val', this.value);
});
See this fiddle
You need to put a for loop outside the code that created the elements:
}).on('change', function () {
var val = $(this).val(),
old = $(this).data('val');
for (var count=0; count<Math.abs(val-old) ; count++)
{
...
}
Update based on comments
See this updated fiddle. There were some problems that were in the original code:
The data was not initialised. Fix: if( !startVal || startVal.length == 0 )
The comparison was not with ints. Fix: inc = (parseInt(val) >= parseInt(old));
Your code is checking for the direction of change between old and new only, not how much difference there is. If it's an increase (of any amount), you add an element; if it's a decrease, you remove one.
You need to wrap that code in a loop and execute it as many times as the difference between old and new.
for (var i=0 ; i<Math.abs(val-old) ; i++) {
if (inc) {
$(input).insertAfter(ele.nextUntil(':not(.name-number-field)').last()
.length ? ele.nextUntil(':not(.name-number-field)').last() : ele);
} else {
ele.nextUntil(':not(.name-number-field)').last().remove();
}
}

How to dynamically add text fields to a form based on a number the user puts in

I'm attempting to make a form that asks the user for a number of units, then asks whether or not they would like those units to be provisioned, and depending on the answer, generates text fields corresponding with the number of units the typed in, along with a text field asking for an account number.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js">
</script>
<script type="text/javascript">
function Getunits(value) {
var units = document.getElementById('units');
for(count=0; count<=units; count++) {
$("<input type='text'>").appendTo("inpane");
}
document.getElementByTag('futureacc').InnerHTML='What is your account number? <input type="text" value="accountnum">';
}
</script>
</head>
<body>
<div id="container">
<form method="post" action="sendcontact.php">
<div id="unitammount" class="inpane">
Number of units ordered: <input type="text" name="units" id="units"/><br />
</div>
<div id="futureacc" class="inpane">
Are these units to be provisioned? <input type="radio" name="select" value="yes" onClick="Getunits('units.value')"/> Yes <input type="radio" name="select" value="no"/> No
</div>
Obviously I would like the new text fields to appear inside the futureacc div and inpane div respectively.
I don't know whether it's the loop that doesn't do anything or that I'm not appending correctly but as I currently have it this does nothing...
Any help would be greatly appreciated.
You had a number of errors with your code. It was confusing because you were mixing jQuery and pure Javascript. It's generally better to just use jQuery if you've decided to use it anyway. Your loop should have been iterating while it was smaller than units.val(), not while it was smaller than or equal to units. innerHTML is spelled with a lowercase "i," and your appendTo selector needed a period before the class name. I went ahead and cleaned up your code so it should work now!
HTML:
<div id="container">
<form method="post" action="sendcontact.php">
<div id="unitammount" class="inpane">
Number of units ordered: <input type="text" name="units" id="units"/>
</div><br>
<div id="futureacc" class="inpane">
Are these units to be provisioned? <input type="radio" name="select" value="yes" onClick="getUnits()"/> Yes <input type="radio" name="select" value="no"/> No <br>
</div>
</form>
</div>​
Javascript:
function getUnits() {
var units = $("#units").val();
for (var count = 0; count < units; count++) {
$("<input type='text' /><br>").appendTo("#futureacc");
}
$("#futureacc").append('<br>What is your account number? <input type="text" placeholder="accountnum">');
}​
WORKING DEMO
var units = document.getElementById('units');
needs to be
var units = document.getElementById('units').value;
you are passing value to onclick but it is a string will not give you exact value anyway you are not using it in you function so it doesnt have any side effect.
also you need to some error check to make sure that user has entered a number
with
for(count=0; count<=units; count++)
You are adding 1 more text box than user entered value. so if user has entered 4 you are creating 5 <= should be changed to <
This is wrong
onClick="Getunits('units.value')"
Instead use this:
onClick="Getunits(units.value)"
try this
$(document).ready(function(){
$('input[name=select]').click(function(){
if($(this).val() ==='yes'){
var numberOfTextboxes = $('#units').val();
for(var i =0; i<numberOfTextboxes; i++){
$('#unitammount').append('<input type="text" />');
}
}
});
});
See the fiddle

Categories