Question
How can I have an element dynamically display the sum of various inputs?
Background
I have several text boxes (with the same class). I have 4 inputs, each with a number. Input 1 is "1", 2 is "2", etc.
I want the fifth box to contain the sum of "1, 2, 3, 4".
Issue
I am struggling with the javascript.
Ideally the fourth box with id final would update as any of the previous boxes are edited.
Can I do it using the classes? that is my intent as the amount of inputs can vary, it will not always be four.
HTML
<input type='text' id='txtFirst' class='copyText' /><br/>
<input type='text' id='txtSecond' class='copyText' /><br/>
<input type='text' id='txtThird' class='copyText' /><br/>
<input type='text' id='final' />
$('.copyText').on('keyup', function(){
var val = 0;
$('.copyText').each(function(){
val = val + (+$(this).val());
})
$('#final').val(val);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<input type='text' id='txtFirst' class='copyText' /><br/>
<input type='text' id='txtSecond' class='copyText' /><br/>
<input type='text' id='txtThird' class='copyText' /><br/>
<input type='text' id='final' />
Try this which uses jQuery (demo using 2.1.0)
$('.copyText').on('keyup', function(){
var val = 0;
$('.copyText').each(function(){
val = val + (+$(this).val());
})
$('#final').val(val);
})
To see the the working demo click here. Or run the code snippet here.
window.onload = _ => {
//get the html elements
const texts = Array.from(document.getElementsByClassName("copyText"));
const out = document.getElementById("final");
//a function for getting all the text values and updating the ouput
function update(){
out.value = texts.map( text => text.value ).join(", ");
}
//await input, then update
texts.forEach( text => text.addEventListener("input", update) );
};
With jQuery get the fields values :
$('.copyText').map(function(){return $(this).val();})
Transform to string with :
.get().join(',')
And assign it to #final with :
$("#final").val();
Conclusion :
$("#final").val($('.copyText').map(function(){return $(this).val();}).get().join(','));
Related
I want to create a form where I will perform an operation with the values entered by the user, but when the function runs, I get NaN return. Thank you in advance for the help.
function test() {
var age = document.getElementsByName("person_age").value;
var weight = document.getElementsByName("person_weight").value;
var size = document.getElementsByName("person_size").value;
document.getElementById("result").innerHTML = weight + size + age;
}
<form>
<input type="text" name="person_age">
<input type="text" name="person_size">
<input type="text" name="person_weight">
<input type="button" value="calculate" onclick="test();">
</form>
<h3 id="result"></h3>`
Output:
NaN
When I get the values from the user and run the function, I get NaN feedback. how can i solve this problem.
There are multiple errors that you have to correct
1) When you use getElementsByName, It will return NodeList array like collection. So you have to get the element by using index as:
var age = document.getElementsByName( "person_age" )[0].value;
2) If you need sum of all three value then you have to convert it into Number type because document.getElementsByName( "person_age" )[0] give you value in String type. So you can do as:
+document.getElementsByName( "person_age" )[0].value
function test() {
var age = +document.getElementsByName("person_age")[0].value;
var size = +document.getElementsByName("person_size")[0].value;
var weight = +document.getElementsByName("person_weight")[0].value;
document.getElementById("result").innerHTML = weight + size + age;
}
<form>
<input type="text" name="person_age">
<input type="text" name="person_size">
<input type="text" name="person_weight">
<input type="button" value="calculate" onclick="test();">
</form>
<h3 id="result"></h3>
Just a Suggestion: You can use Document.getElementById if you want to directly access the value. Just add an ID property in your element. It will return a string value, convert that to int and you're good to go.
function test() {
var age = document.getElementById("person_age").value;
var weight = document.getElementById("person_weight").value;
var size = document.getElementById("person_size").value;
document.getElementById("result").innerHTML = parseInt(weight) + parseInt(size) + parseInt(age);
}
<form>
<input type="text" name="person_age" id="person_age">
<input type="text" name="person_size" id="person_size">
<input type="text" name="person_weight" id="person_weight">
<input type="button" value="calculate" onclick="test();">
</form>
<h3 id="result"></h3>
getElementsByName will always return an array-like nodelist so, if you were to use it you would need to access the first index [0]. Instead add a class to each input and use querySelector to target it.
The value of an input will always be a string (even if the input is type "number"), so you need to coerce it to a number, either by using Number or by prefixing the value with +.
So, in this example I've updated the HTML a little by adding classes to the inputs, and changing their type to "number", and removing the inline JS, and updated the JS so that the elements are cached outside of the function, an event listener is added to the button, and the values are correctly calculated.
// Cache all the elements using querySelector to target
// the classes, and add an event listener to the button
// that calls the function when it's clicked
const ageEl = document.querySelector('.age');
const weightEl = document.querySelector('.weight');
const sizeEl = document.querySelector('.size');
const result = document.querySelector('#result');
const button = document.querySelector('button');
button.addEventListener('click', test, false);
function test() {
// Coerce all the element values to numbers, and
// then display the result
const age = Number(ageEl.value);
const weight = Number(weightEl.value);
const size = Number(sizeEl.value);
// Use textContent rather than innerHTML
result.textContent = weight + size + age;
}
<form>
<input type="number" name="age" class="age" />
<input type="number" name="size" class="size" />
<input type="number" name="weight" class="weight" />
<button type="button">Calculate</button>
</form>
<h3 id="result"></h3>`
I have many input fields (3 on each row), that basically do the same thing:
Input1 * Input2 = DisabledInput=result
Input3 * Input4 = DisabledInput=result
...
What would be the best way to multiply input fields on each row with js?
Doing it with getElementsById works, but that means creating several dozen IDs, even though the logic on each row is the same.
<div class="row">
<input class="input first" id="id1" type="text" name="first" oninput="calculate()" value="" placeholder="Enter number">
<input class="input second" id="id2" type="text" name="second" oninput="calculate()" value="" placeholder="Enter number">
<input class="input result" id="idResult" type="text" name="result" oninput="calculate()" value="" placeholder="Enter number">
</div>
function calculate() {
var first = document.getElementById('id1').value;
var second = document.getElementById('id2').value;
var result = document.getElementById('idResult');
var finalResult = id1 * id2;
idResult.value = Math.round(finalResult * 100) / 100;
}
I tried using
var get = function(clsName) {
return document.getElementsByClassName(clsName)[0];
};
get('result').innerHTML = +get('first').innerHTML * +get('second').innerHTML;
But it's not working. I'm just wondering what would the best approach be to problems like this? Surely not entering 50 different Ids for doing the same thing?
Update
New Solution
Using .class Attribute
See Demo 2.
If [name] is too busy of an attribute and you are concerned with possible conflicts, .class can be just as effective with this particular solution. In Demo 2 all [name] attributes are now .class attributes. The .className property is used instead of .name property. If any of your targeted elements have more than one class then use .classList.contains() property and method.
Original Solution
Using [name] Attribute
See Demo 1.
As long as your layout pattern is the same consistently
<input...> <input...> <output...>
You can have an unlimited number of input/output combos that operate independently from one another by delegating an event. The demo provided has a form tag that manages all form controls nested within it when the input event is triggered. An input event occurs whenever a form control gets data from a user by typing or selecting. The terse syntax used to reference the form tag (see first comment in demo) is from the HTMLFormElement interface. Also, instead of another input for the result, use an output tag instead, and use type='number' on inputs which will facilitate correct input. Details are commented in demo.
Note: I intentionally left that expression out of the function intentionally (it looked excessive to me since context or an explanation wasn't provided about said expression). If you still want to use it just replace line F with the following:
let product = origin.valueAsNumber * B.valueAsNumber;
C.value = Math.round(product * 100) / 100;
Do the same for line X and replace B.valueAsNumber; with A.valueAsNumber;
Demo 1
/*
Register the first form on the page to the input event
When any input within the form gets user data call function multiply()
*/
document.forms[0].oninput = multiply;
/** multiply()
//A - Pass Event Object
//B - Find input getting the user data - e.target always points to
the input getting data or button getting clicked, etc.
//C - if origin's [name=factorA]...
//D - ...then B is the tag after origin...
//E - ...and C is the tag after B...
//F - ...Set the value of C as the product of A and B
All form control values are strings not numbers, so once a
value is extracted from a form control it must be converted
to a number -- input.valueAsNumber is one of several ways
to do so.
- The second control statement handles input event if origin is
[name=factorB]
*/
function multiply(e) { //A
const origin = e.target; //B
if (origin.name === 'factorA') { //C
let B = origin.nextElementSibling; //D
let C = B.nextElementSibling; //E
C.value = origin.valueAsNumber * B.valueAsNumber; //F
} else if (origin.name === 'factorB') {
let A = origin.previousElementSibling;
let C = origin.nextElementSibling;
C.value = origin.valueAsNumber * A.valueAsNumber; //X
} else {
return false;
}
}
:root {
font: 700 3vw/1.2 Consolas
}
input,
output,
label {
display: inline-block;
font: inherit;
text-align: right;
}
input {
width: 30vw
}
<form>
<fieldset>
<legend>Multiplication</legend>
<label>
<input name='factorA' type='number' value='0'> × <input name='factorB' type='number' value='0'> = <output name='product'>0</output>
</label><br>
<label>
<input name='factorA' type='number' value='0'> × <input name='factorB' type='number' value='0'> = <output name='product'>0</output>
</label><br>
<label>
<input name='factorA' type='number' value='0'> × <input name='factorB' type='number' value='0'> = <output name='product'>0</output>
</label><br>
</fieldset>
</form>
Demo 2
/*
Register the first form on the page to the input event
When any input within the form gets user data call function multiply()
*/
document.forms[0].oninput = multiply;
/** multiply()
//A - Pass Event Object
//B - Find input getting the user data - e.target always points to
the input getting data or button getting clicked, etc.
//C - if origin's .factorA...
//D - ...then B is the tag after origin...
//E - ...and C is the tag after B...
//F - ...Set the value of C as the product of A and B
All form control values are strings not numbers, so once a
value is extracted from a form control it must be converted
to a number -- input.valueAsNumber is one of several ways
to do so.
- The second control statement handles input event if origin is
.factorB
*/
function multiply(e) { //A
const origin = e.target; //B
if (origin.className === 'factorA') { //C
let B = origin.nextElementSibling; //D
let C = B.nextElementSibling; //E
C.value = origin.valueAsNumber * B.valueAsNumber; //F
} else if (origin.className === 'factorB') {
let A = origin.previousElementSibling;
let C = origin.nextElementSibling;
C.value = origin.valueAsNumber * A.valueAsNumber; //X
} else {
return false;
}
}
:root {
font: 700 3vw/1.2 Consolas
}
input,
output,
label {
display: inline-block;
font: inherit;
text-align: right;
}
input {
width: 30vw
}
<form>
<fieldset>
<legend>Multiplication</legend>
<label>
<input class='factorA' type='number' value='0'> × <input class='factorB' type='number' value='0'> = <output class='product'>0</output>
</label><br>
<label>
<input class='factorA' type='number' value='0'> × <input class='factorB' type='number' value='0'> = <output class='product'>0</output>
</label><br>
<label>
<input class='factorA' type='number' value='0'> × <input class='factorB' type='number' value='0'> = <output class='product'>0</output>
</label><br>
</fieldset>
</form>
With getElementsByClassName
total = 0
for (instance of document.getElementsByClassName(clsName)) {
total+=parseInt(instance.value)
}
console.log(total)
An example for your problem
total = 0
i = 1
for (instance of document.getElementsByClassName(clsName)) {
if (i%3!=0) {
total+=parseInt(instance.value)
i++
} else {
instance.value = total
total = 0
i = 1
}
}
With getElementById
ids = ['id1', 'id2', 'idResult']
for (let id of ids) {
console.log(document.getElementById(id).value)
}
I want to create a fill in the blank quizz web site.
My problem is putting a different name="" value of all inputs.
So I create a function Who change a string giving into input.
But the problem is they have all the same name (inpName1).
What I want to do is giving them a diffrent names (inpName1,inpName2,inpName3...) so I can recuperate them later into DB
var i=0;
function MyFunction() {
var str = document.getElementById("myTextArea").value;
var res = str.replace(/#champ/g, "<input type='text' name='inpName"+ i++ +"'>");
document.getElementById("finalText").innerHTML = res;
}
Instead of inpName1, inpName2 etc use [] notation in name attribute:
<input type='text' name='inpName[]'>
<input type='text' name='inpName[]'>
<input type='text' name='inpName[]'>
<input type='text' name='inpName[]'>
In this case your values will be available on server via $_POST['inpName'] array.
I had one row with three fields: received, issue, balance
<input type="text" name="rcv" class="rcv"/>
<input type="text" name="issue" class="issue"/>
<input type="text" name="blnc" class="balance"/>
I calculated the balance for each row easily, but how do I calculate more than one row?
Each row has receive, issue and balance fields.
How do I calculate each row's balance field?
I tried like this for multiple row but it's not working:
$('.t_rtn, .t_rcv').each(function(){
$(this).on('blur',function(){
var totalRcv = $('.t_rcv').val();
var totalRtn = $('.t_rtn').val();
// console.log( $('t_rtn').next('.consume').val() );
$('t_rtn').next('.consume').val(totalRcv-totalRtn);
});
you need to parse The value of textbox as it returns string not int
$('.t_rtn, .t_rcv').each(function(){
$(this).on('blur',function(){
var totalRcv = parseInt($('.t_rcv').val()) || 0;
var totalRtn = parseInt($('.t_rtn').val()) || 0;
// console.log( $('t_rtn').next('.consume').val() );
$('t_rtn').next('.consume').val(totalRcv-totalRtn);
});
If your code is being run on document.ready it will only be applied to elements which exist at that point.
You'd be better with :
$(document).on('blur','.t_rtn, .t_rcv',function(){
var val = $(this).val();
...
});
try this..
$(document).on('blur','.receive, .return', function()
{
var $row = $(this).closest(".row");
var totalRcv = parseInt($row.find('.receive').val()) || 0;
var totalRtn = parseInt($row.find('.return').val()) || 0;
$row.find('.balance').val(totalRcv - totalRtn);
});
In addition to parsing the string values into integers you also need to use the correct selectors for those input elements. t_rtn is not the right class name, for example. And if doing this in rows you will want to grab the correct element from the current row (you already did this correctly for the consume field)
Fixed html (Example.. I chose to use div with class name = row):
<div class='row'>
<input type="text" name="rcv" class="receive"/>
<input type="text" name="issue" class="return"/>
<input type="text" name="blnc" class="balance"/>
</div>
<div class='row'>
<input type="text" name="rcv" class="receive"/>
<input type="text" name="issue" class="return"/>
<input type="text" name="blnc" class="balance"/>
</div>
<div class='row'>
<input type="text" name="rcv" class="receive"/>
<input type="text" name="issue" class="return"/>
<input type="text" name="blnc" class="balance"/>
</div>
Fixed code:
$(document).on('blur','.receive, .return', function()
{
var $row = $(this).closest(".row");
var totalRcv = parseInt($row.find('.receive').val()) || 0;
var totalRtn = parseInt($row.find('.return').val()) || 0;
$row.find('.balance').val(totalRcv - totalRtn);
});
I took the liberty of fixing some inconsistencies with the class names used. I tried to match them up to the variables for totalRcv and totalRtn so that now the balance shows as receipt minus return. If the user enters non-numeric data, it defaults the value to 0 before calculating.
Example fiddle here: http://jsfiddle.net/cp81g4nf/1/
I think problem is because you are subtracting 2 Strings. .val returns an String.
Convert them in number before subtracting like bellow
$('t_rtn').next('.consume').val((+totalRcv)-(+totalRtn));
i am dynamically building a page. This page needs to read information from input tags but it is dynamic. Should i set up stuff to be an array since i am looking at
I want to preserve datasets.
<script>
function adjustPilots(){
var pilots = $("#numPilots").val();
var info = '<td><table>'+
'<tr><td>Minumum Collateral</td><td colspan="2"><input type = "text" size = "10" maxLength = "6" /> to <input type = "text" size = "10" maxLength = "6" /></td></tr>'+
'<tr><td>Reward</td><td colspan="2"><input type = "text" size = "10" maxLength = "6" /> to <input type = "text" size = "10" maxLength = "6" /></td></tr>'+
'<tr><td>Volume</td><td colspan="2"><input type = "text" size = "10" maxLength = "7" /> to <input type = "text" size = "10" maxLength = "7" /></td></tr>'+
'<tr><td>Start: </td><td><input type = "text" name = "s" id = "s" class = "s" value autocomplete = "off"></td></tr>'+
'<tr><td>End: </td><td><input type = "text" name = "e" id = "e" class = "e" value autocomplete = "off"></td></tr>'+
'</table></td>';
for(var i = 0; i < Number(pilots); i++){
$("#pilotrow").append(info);
}
}
</script>
<body>
<form>
<table>
<tr><td>Number of Pilots</td><td colspan="2"><input id = "numPilots" type = "text" size="3" maxLength="3" onchange = 'adjustPilots()' /></td></tr>
<tr id = "pilotrow"></tr>
<tr><td><input type = "submit" name = "submit"></td></tr>
</table>
</form>
</body>
An option i was thinking was to just not use a form, and build it with javascript. Then make a JSON object and use AJAX to send it to the server. Is that a solid way of doing it, or is there a better idea?
There are at least 2 way to do that.
Without javascript, you cate a form with array of element like this
<input type="text" name="input[]"/>
<input type="text" name="input[]"/>
<input type="text" name="input[]"/>
<input type="text" name="input[]"/>
in php
$inputs = $_POST['input'];
for($inputs as $inp){
}
With ajax and jquery, you can just simply serialize your form and post to backend
You can achieve that by using the name attribute in your inputs. Like so:
<input type="text" name="pilots[]" />
Then you would probably want to keep track of how many pilots you are adding that way you can send an indexed array. Like so:
<input type="text" name="pilots[0][minumumCollatural]" />
<input type="text" name="pilots[0][reward]" />
<input type="text" name="pilots[0][volume]" />
That way when you submit your form to the server, your array of pilots will look something like:
$pilots = $_POST['pilots'];
// Which looks like
array(
[0] => array
(
[minumumCollatural] => // Some number
[reward] => // Some number
)
[1] => array
(
[minumumCollatural] => // Some number
[reward] => // Some number
)
)
Try utilizing the hidden input tag to send data in whatever fashion you please. For instance:
<input type="hidden" name="myinput" id="myinput" />
Now in JS:
$("form").submit(function() {
$("input").not("#myinput").each(function() {
$("#myinput").val($("#myinput").val()+$(this).val());
// you can format anyway you want this is just an example
});
});
Hope this helps!