I have this function (it works) to create a number of dynamic inputs:
<script type='text/javascript'>
var arr = [];
function espacioArreglos() {
// Number of inputs to create
var number = document.getElementById("cantidadArreglos").value;
// Container <div> where dynamic content will be placed
var container = document.getElementById("container");
// Clear previous contents of the container
while (container.hasChildNodes()) {
container.removeChild(container.lastChild);
}
for (i=0;i<number;i++){
// Append a node with a random text
container.appendChild(document.createTextNode("Arreglo #" + (i+1)));
// Create an <input> element, set its type and name attributes
var input = document.createElement("input");
input.type = "number";
input.name = "arreglo" + i;
//set ID to each input to calculate summatory
var inputId = 'input-' + i;
input.setAttribute('id', inputId);
arr.push(inputId);
input.setAttribute('onchange', function() {
var sum = 0;
arr.forEach(function(val) {
var inputVal = document.getElementById(val).value;
if (inputVal) sum += inputVal;
});
document.getElementById('totalPlacas').value = sum;
});
container.appendChild(input);
// Append a line break
container.appendChild(document.createElement("br"));
}
}
</script>
And now I want to display the sum of the input values. Here is the HTML:
<tr>
<td align="center" bgcolor="#D4D4D4">Cantidad de arreglos:</td>
<td align="center" bgcolor="#D4D4D4"><input type="number" id="cantidadArreglos" onchange="espacioArreglos();" size="1"></td>
</tr>
<tr>
<td align="center" bgcolor="#D4D4D4">Cantidad de placas:</td>
<td bgcolor="#FFFF00"><div id="container"/></td>
</tr>
<tr>
<td align="center" bgcolor="#D4D4D4">Total de placas:</td>
<td align="center" bgcolor="#D4D4D4"><div id="totalPlacas"></div></td>
</tr>
So, you enter a number in "Cantidad de arreglos", it calls the function "espacioArreglos" and then I want to use the values that I will enter on the generated inputs to calculate its summatory, which should be displayed at the div "totalPlacas". However, nothing appears... Whats the problem with my code?
There are some changes that need to be done:
First, change the
<div id="container"/> to <div id="container"></div> as the shortcut on a div breaks the HTML causing that totalPlacas doesn't exists.
Second, add the onchange event using
input.onchange = function() {...}
Now the result should be added to the 'totalPlacas' div using .innerText = sum instead using the .value = sum.
Now you can check that the result displayed is a concatenation of strings instead adding the numbers, this can be solved replacing
if (inputVal) sum += inputVal;
with
if (inputVal) sum += parseInt(inputVal);
You should add some kind of validation to avoid an error when the user types a letter or symbol instead a number.
Hope it works!
You will need to assign a unique ID to the input elements, so you can reference them using document.getElementById().
Something like:
input.setAttribute("id", 'input' + i);
How about assigning id's to the dynamic inputs and storing them in an array. First, outside of the function (global scope) define an empty array:
var arr = [];
In your for loop:
var inputId = 'input-' + i;
input.setAttribute('id', inputId);
arr.push(inputId);
input.setAttribute('onchange', function() {
var sum = 0;
arr.forEach(function(val) {
var inputVal = document.getElementById(val).value;
if (inputVal) sum += inputVal;
});
// do something with the sum
console.log(sum)
});
Related
Update: Put in more context.
Update 2: The sum isn't adding correctly now, and the initial sum doesn't appear until I edit one of the values.
I am trying to add contentEditable items from a table in JavaScript.
The three rows I'd like to add are named "string1", "string2", and "string3", and "total" is the id of the row that displays the sum of all three strings.
I attempted to use parseInt to add the numerical values of the numbers already in the table, but the total sum is incorrect for some reason. Also, the the sum of the initial set of numbers is blank until I one of the values. How do I get it to appear when I open the file?
Below is the code:
<body>
<table>
<tr>
<td>First:</td>
<td id="string1" oninput="myFunction()">100</td>
</tr>
<tr>
<td>Second:</td>
<td id="string2" oninput="myFunction()">200</td>
</tr>
<tr>
<td>Third:</td>
<td id="string3" oninput="myFunction()">100</td>
</tr>
<tr>
<td>Sum</td>
<td id="total"></td>
</tr>
</table>
</body>
<script type="text/javascript">
document.getElementById("string1").contentEditable = true;
document.getElementById("string2").contentEditable = true;
document.getElementById("string3").contentEditable = true;
var integer1 = document.getElementById("string1").innerText;
var integer2 = document.getElementById("string2").innerText;
var integer3 = document.getElementById("string3").innerText;
var sum = parseInt(integer1) + parseInt(integer2) + parseInt(integer3);
function myFunction() {
document.getElementById("total").innerHTML = sum;
}
</script>
What am I doing wrong?
Its here:
function myFunction() {
document.getElementById("total").innerHTML = sum;
}
Thats an declaration of an function, you just declare it.
You also need to execute that function to make it work with:
myFunction()
Your code looks like this then:
<script type="text/javascript">
document.getElementById("string1").contentEditable = true;
document.getElementById("string2").contentEditable = true;
document.getElementById("string3").contentEditable = true;
function myFunction() {
var integer1 = document.getElementById("string1").innerText;
var integer2 = document.getElementById("string2").innerText;
var integer3 = document.getElementById("string3").innerText;
var sum = parseInt(integer1) + parseInt(integer2) + parseInt(integer3);
}
myFunction();
</script>
You're not calling myFunction() so that code never gets executed.
To make it calculate whatever is in the elements string1, string2, string3 you need to listen for a change and then calculate the sum:
document.getElementById("string1").contentEditable = true;
document.getElementById("string2").contentEditable = true;
document.getElementById("string3").contentEditable = true;
function myFunction() {
// Table cells do not have .value property so we use .innerText
var integer1 = document.getElementById("string1").innerText;
var integer2 = document.getElementById("string2").innerText;
var integer3 = document.getElementById("string3").innerText;
var sum = parseInt(integer1, 10) + parseInt(integer2, 10) + parseInt(integer3, 10);
document.getElementById("total").innerHTML = isNaN(sum) ? 0 : sum;
}
document.getElementById("string1").addEventListener("input", myFunction);
document.getElementById("string2").addEventListener("input", myFunction);
document.getElementById("string3").addEventListener("input", myFunction);
// do initial calculation
myFunction();
Also you should always pass the second parameter (radix) of parseInt.
I have a table where one td gets 1 if a checkbox is checked and I would like to multiple this td with another and display it in a third one.
See the html here:
<div>
<input type="checkbox" id="fut1">check</input>
</div>
<table border="1" cellpadding="10" id="countit">
<tr>
<td id="td1"></td>
<td id="td2">5000</td>
<td id="td3"></td>
</tr>
</table>
And here is the js:
$('#fut1').change(function () {
if ($(this).is(":checked")) {
$('#td1').text('1');
} else {
$('#td1').text('0');
}
});
$('#td1').change(function () {
var me = $('#td1').value;
var ar = $('#td2').value;
var sum = me * ar;
$('#td3').text(sum);
});
$('#td1').change(function () { // <--- td elements don't have a change event listener/handler
var me = $('#td1').value; // <--- td elements don't have a value
var ar = $('#td2').value; // <--- td elements don't have a value
var sum = me * ar;
$('#td3').text(sum);
});
If you want to do it this way:
$('#fut1').change(function () {
if ($(this).is(":checked")) {
$('#td1').text('1');
} else {
$('#td1').text('0');
}
callTdChange();
});
function callTdChange() {
var me = parseInt($('#td1').text());
var ar = parseInt($('#td2').text());
var sum = me * ar;
$('#td3').text(sum);
}
Of course, the better way should be to use form elements (inputs) in the case you want to save your data to a server, or use change behaviors.
#td1 doesn't support the change event, because that's only meant for interactive elements (like input, select, or textarea).
You can either do the calculation in your first event listener in #fut1, or declare an input element inside #td1.
So, I have the following jquery code that clones an element when the input value in a certain field increases.
$(document).ready(function(){
$("#nmovimentos").change(function () {
var direction = this.defaultValue < this.value
this.defaultValue = this.value;
if (direction)
{
var $div = $('div[id^="novomov"]:last');
var num = parseInt( $div.prop("id").match(/\d+/g), 10 ) +1;
var $clone = $div.clone().prop('id', 'novomov'+ num)
$clone.insertAfter('[id^="novomov"]:last');
}
else $('[id^="novomov"]:last').remove();
});
});
However, it clones a div that contains part of a form with lots of input fields.
<div id="novomov1" class="novomov">
<table id="tab">
<tr name="linear1" id="linear1">
<td>
Cardinalidade:<input type="text" name="card1" id="card1" value=""><br>
Angulo 1:<input type="text" name="param1" id="angulo1" value=""><br>
Angulo 2:<input type="text" name="param2" id="angulo2" value=""><br>
Tamanho:<input type="text" name="param3" id="tamanho1" value=""><br>
Descricao:<input type="text" name="descricao1" id="descricao1" value=""><br>
Tempo:<input type="text" name="tempo1" id="tempo1" value=""><br>
</td></tr></table></div>
I need to change the names of all the cloned div's descendents, in order to pass these paramaters to a data base. I thought of incrementing the names by 1, using the var num in the jquery function. However I'm I little lost.. so, any clues on how to do that? thank you very much!
Code changed to retrieve all the inputs inside the cloned div and change its name/id.
<script>
$(document).ready(function(){
$("#nmovimentos").change(function () {
var direction = this.defaultValue < this.value
this.defaultValue = this.value;
if (direction)
{
var $div = $('div[id^="novomov"]:last');
var num = parseInt( $div.prop("id").match(/\d+/g), 10 ) +1;
var $clone = $div.clone().prop('id', 'novomov'+ num)
$clone.insertAfter('[id^="novomov"]:last');
// get all the inputs inside the clone
var inputs = $clone.find('input');
// for each input change its name/id appending the num value
$.each(inputs, function(index, elem){
var jElem = $(elem); // jQuery element
var name = jElem.prop('name');
// remove the number
name = name.replace(/\d+/g, '');
name += num;
jElem.prop('id', name);
jElem.prop('name', name);
});
}
else $('[id^="novomov"]:last').remove();
});
});
</script>
Instead of parsing the id of the element to get the number you should use the data attribute. Also since you are using jQuery you can use .last() to get the last element with that id. Hope this helps.
$('#nmovimentos').on('change', function () {
var direction = this.defaultValue < this.value,
$last = $('#novomov').last(),
$clone,
num;
this.defaultValue = this.value;
if (direction) {
// add id in a data attribute instead of parsing the id
num = parseInt($last.data('id'), 10) + 1;
// set clone id data attribute to have the latest number
$clone = $last.clone().data('id', num);
// add clone after the last div
$last.after($clone);
} else {
$last.remove();
}
});
JavaScript name change of cloned input element "terminal0" isn't saving and/or reverting back to original name after function ends. All other name/id changes work but first element name change reverts back after function completes. Even the first element "terminal0" id change works successfully. I've tested and confirmed name change does work before function exits by placing an alert(cTerm.name) at the end of it. Anyone know reason why name change isn't working for first input element?
<tr id="tr1">
<td id="tr1Td0">
Terminal <input type="checkbox" name="terminal0" id="terminal0" value="0" onClick="cbUpdate()">
<br>
Imager <input type="checkbox" name="imager0" id="imager0" value="0" onClick="cbUpdate()">
</td>
</tr>
</tbody>
</table>
function addTable()
{
var gssTable = document.getElementById("gssTable");
var currTables = gssTable.rows[0].cells.length;
var selNum = document.getElementById("sNum").value;
var tr0 = document.getElementById("tr0");
var tr1 = document.getElementById("tr1");
var br = document.createElement('br');
for(x=currTables; x < selNum; x++)
{
var tr0Td0 = tr0.insertCell(-1);
var setID0 = document.getElementById("setID0");
var cSetID = setID0.cloneNode(true);
cSetID.id = "setID" + x;
cSetID.name = "setID" + x;
tr0Td0.appendChild(cSetID);
var tr1Td0 = tr1.insertCell(-1);
tr1Td0.innerHTML="Terminal";
var terminal0 = document.getElementById("terminal0");
var cTerm = terminal0.cloneNode(true);
cTerm.id = "test" + x;
cTerm.name = "test" + x;
tr1Td0.appendChild(cTerm);
tr1Td0.appendChild(br);
tr1Td0.innerHTML = tr1Td0.innerHTML + "Imager"
var imager0 = document.getElementById("imager0");
var cImager = imager0.cloneNode(true);
cImager.id = "imager" + x;
cImager.name = "imager" + x;
tr1Td0.appendChild(cImager);
}
while (currTables > selNum)
{
tr1.deleteCell(-1);
tr0.deleteCell(-1);
currTables = currTables - 1;
}
Setting the innerHTML makes the browser re-render that element and its contents. Since you are doing it each iteration of the loop, you are probably causing a race condition where innerHTML hasn't been updated to the latest effects of the appendChild calls above it.
So instead of setting innerHTML each time you can just create a Text node, with createTextNode, and append it.
tr1Td0.appendChild(document.createTextNode("Imager"));
I have a table and I want to add and display the SUM of a td value in a div when a user access the page.
<table>
<thead>
<tr>
<th>Value</td>
</tr>
</thead>
<tbody>
<tr>
<td class="d">PHP <?php echo number_format($l['target_daily'], 2) ?></td>
</tr>
</tbody>
</table>
And Some javascript to get sum duning page load
<script>
$(calculateSumm);
function calculateSumm() {
var sum = 0;
$(".d").each(function() {
if(!isNaN(this.value) && this.value.length!=0) {
sum += parseFloat(this.value);
}
});
$('#result').html(sum);
};
</script>
<div id="result>//This will display sum values but returns 0</div>
What I am lacking here?
The issues are that you're using this.value, which td elements don't have (value is just on input elements and similar), and you have PHP at the beginning of the text of the cells.
See code comments:
$(calculateSumm);
function calculateSumm() {
var sum = 0;
$(".d").each(function() {
// Get the text of the cell
var val = $(this).text()
// Remove the PHP at the beginning
val = val.replace(/^\s*PHP\s*/, '');
if (val.length) {
// Parse it
val = parseFloat(val);
if (!isNaN(val)) {
// Add it
sum += val;
}
}
});
$('#result').html(sum);
};
The bit where we're replacing the "PHP" could use some extra explanation:
val = val.replace(/^\s*PHP\s*/, '');
That means: "Match optional whitespace followed by PHP followed by optional whitespace at the beginning of the string, and replace it with an empty string".
Side note: There's no reason to wonder what's going wrong with your code. Your browser has a JavaScript debugger built into it, which lets you set breakpoints in your code to pause it, inspect variables, single-step through the code to watch it run, etc. Look in the menus for the "Dev Tools" (F12 and/or Ctrl+Shift+I on most browsers).
Try this:
<script>
$(calculateSumm);
function calculateSumm() {
var sum = 0;
$(".d").each(function() {
sum += parseFloat($(this).text());
});
$('#result').html(sum);
};
</script>
The value property is not available for TD elements. So I replaced the this.value with $(this).text() which uses jquery to get the textual value from the inner part of the td element.
As suggested by #T.J Crowder
<script>
$(calculateSumm);
function calculateSumm() {
var sum = 0;
$(".d").each(function() {
// Get the text of the cell
var val = $(this).text()
// Remove the PHP at the beginning
val = val.replace(/^\s*PHP\s*/, '');
if (val.length) {
// Parse it
val = parseFloat(val);
if (!isNaN(val)) {
// Add it
sum += val;
}
}
});
//$('#result').html(sum);
$("#result").html(sum.toFixed(2).replace(/(^\d{1,3}|\d{3})(?=(?:\d{3})+(?:$|\.))/g, '$1,'));
};
Now it works.Perfect