I am using jquery to loop through table rows and save the data. If the table has 200 rows it is performing slow. I am getting the javascript message "Stop Running this script" in IE when I call this method. Following is the code I am using to loop through table rows. Can you please let me know if there is a better way to do this.
function SaveData() {
var $table = $('#' + gridid);
var rows = $table.find('tbody > tr').get();
var transactions = [];
var $row, empno, newTransaction, $rowChildren;
$.each(rows, function(index, row) {
$row = $(row);
$rowChildren = $row.children("td");
if ($rowChildren.find("input[id*=hRV]").val() === '1') {
empno = $rowChildren.find("input[id*=tEmpno]").val();
newTransaction = new Array();
newTransaction[0] = company;
newTransaction[1] = $rowChildren.find("input[id*=tEmpno]").val();
newTransaction[2] = $rowChildren.find("input[id*=tPC]").val();
newTransaction[3] = $rowChildren.find("input[id*=hQty]").val();
newTransaction[4] = $rowChildren.find("input[id*=hPR]").val();
newTransaction[5] = $rowChildren.find("input[id*=tJC]").val();
newTransaction[6] = $rowChildren.find("input[id*=tL1]").val();
newTransaction[7] = $rowChildren.find("input[id*=tL2]").val();
newTransaction[8] = $rowChildren.find("input[id*=tL3]").val();
newTransaction[9] = $rowChildren.find("input[id*=tL4]").val();
newTransaction[10] = $rowChildren.find("input[id*=tL5]").val();
newTransaction[11] = $rowChildren.find("input[id*=tL6]").val();
newTransaction[12] = $rowChildren.find("input[id*=tL7]").val();
newTransaction[13] = $rowChildren.find("input[id*=tL8]").val();
newTransaction[14] = $rowChildren.find("input[id*=tL9]").val();
newTransaction[15] = $rowChildren.find("input[id*=tL10]").val();
newTransaction[16] = $rowChildren.find("input[id*=tSF]").val();
newTransaction[17] = $rowChildren.find("input[id*=tCG]").val();
newTransaction[18] = $rowChildren.find("input[id*=tTF]").val();
newTransaction[19] = $rowChildren.find("input[id*=tWK]").val();
newTransaction[20] = $rowChildren.find("input[id*=tAI]").val();
newTransaction[21] = $rowChildren.find("input[id*=tWC]").val();
newTransaction[22] = $rowChildren.find("input[id*=tPI]").val();
newTransaction[23] = "E";
var record = newTransaction.join(';');
transactions.push(record);
}
});
if (transactions.length > 0) {
var strTransactions = transactions.join('|');
//send data to server
//here ajax function is called to save data.
}
}
The html structure for the table row is like this
<tr class="rgRow" id="ctl00_c_PETV2_1_gB_ctl00__12">
<td>
Delete
</td><td>
<input type="text" value='385 ' id="tEmpno" />
<input name="ctl00$c$PETV2_1$gB$ctl00$ctl28$hRV" type="hidden" id="ctl00_c_PETV2_1_gB_ctl00_ctl28_hRV" value="1" />
<input name="ctl00$c$PETV2_1$gB$ctl00$ctl28$hRC" type="hidden" id="ctl00_c_PETV2_1_gB_ctl00_ctl28_hRC" value="0" />
</td><td style="width:100px;">
<input type="text" value='Barron, Pamela J.' id="tEE" readonly="readonly" />
</td><td>
<input type="text" value='OT ' id="tPC" />
</td><td>
<input type="text" value='7.00' id="tQty" class="right" />
<input type="hidden" name="ctl00$c$PETV2_1$gB$ctl00$ctl28$hQty" id="ctl00_c_PETV2_1_gB_ctl00_ctl28_hQty" value="7.00000" />
</td><td>
<input type="text" value='22.00' id="tPR" class="right" />
<input type="hidden" name="ctl00$c$PETV2_1$gB$ctl00$ctl28$hPR" id="ctl00_c_PETV2_1_gB_ctl00_ctl28_hPR" value="22.000000" />
</td><td>
<input type="text" value='231.00' id="tAmt" class="right" readonly="readonly" />
</td><td>
<input type="text" value='300 ' id="tJC" />
</td><td>
<input type="text" value='50 ' id="tL1" />
</td><td>
<input type="text" value='23 ' id="tL2" />
</td><td>
<input type="text" value='001 ' id="tL3" />
</td><td>
<input type="text" value=' ' id="tL4" />
</td><td>
<input type="text" value='1 ' id="tSF" />
</td><td>
<input type="text" value='1' id="tCG" />
</td><td>
<input type="text" value='B' id="tTF" />
</td><td>
<input type="text" value='0' id="tWk" />
</td><td>
<input type="text" value='Y' id="tAI" />
</td><td>
<input type="text" value='8810 ' id="tWC" />
</td><td style="width:50px;">
<input type="text" value='' id="tPI" />
</td>
</tr>
Try minimizing your use of jQuery find(). Its performance is really bad on older browsers. Perhaps use good old getElementsByTagName() instead, which is implemented natively even on IE6. Pseudocode:
get list of tr elements;
for each tr element:
get list of input elements descending from current tr element;
for each input:
if input.id matches x
if input.id matches y
if input.id matches z
Hope this helps.
Replace the repeated calls to find by splitting out that part of the id and then doing a var index = $.inArray(idFragment, ['', 'tEmpno', 'hQty']); call or similar strategy to determine the input's position in the transaction array.
Make as few searches on the DOM as possible. Prefer |= over *= selectors if possible.
Or, if possible, modify the serialize function in jQuery as needed and use the index of the input to determine its position in the transaction array.
Related
How do I sum the two highest values from a list of inputs using JavaScript?
I've tried the below, but I get 4 instead of 5:
<table id="tableID">
<tr>
<td> <input name="name" class="compulsory1" type="text" value="1" /> </td>
<td> <input name="name1" class="compulsory1" type="text" value="3" /> </td>
<td> <input name="name2" class="compulsory1" type="text" value="2" /> </td>
<td>
<script type="text/javascript">
var tdsCompulsory = document.getElementsByClassName('compulsory1');
var len = tdsCompulsory.length;
var cDatax = [];
var cData = cDatax.reverse();
sum = 0;
for(var i = 0; i < 2; i++){
cData.push(tdsCompulsory[i].value);
sum += +tdsCompulsory[i].value;
}
alert (sum);
</script>
</td>
</tr>
</table>
First you find the two highest values, and then sum them together. I'd probably do it something like this:
document.getElementById("the-button").onclick = function() {
// Get the values as numbers
var values = Array.prototype.map.call(
document.getElementsByClassName('compulsory1'),
function(input) {
return +input.value; // + converts to number
}
);
// Put them in order *highest* to *lowest*
values.sort(function(left, right) {
return right - left;
});
// Add the first two
var result = values[0] + values[1];
console.log(values[0] + " + " + values[1] + " = " + result);
};
<input name="name" class="compulsory1" type="text" value="1" />
<input name="name1" class="compulsory1" type="text" value="3" />
<input name="name2" class="compulsory1" type="text" value="2" />
<input id="the-button" type="button" value="Run">
More about that Array.prototype.map.call thing in this answer about looping through arrays and array-like things.
But if you specifically want to use reverse, you'd do that after the sort:
document.getElementById("the-button").onclick = function() {
// Get the values as numbers
var values = Array.prototype.map.call(
document.getElementsByClassName('compulsory1'),
function(input) {
return +input.value; // + converts to number
}
);
// Put them in order lowest to highest
values.sort(function(left, right) {
return left - right;
});
// Then reverse that
values.reverse();
// Add the first two
var result = values[0] + values[1];
console.log(values[0] + " + " + values[1] + " = " + result);
};
<input name="name" class="compulsory1" type="text" value="1" />
<input name="name1" class="compulsory1" type="text" value="3" />
<input name="name2" class="compulsory1" type="text" value="2" />
<input id="the-button" type="button" value="Run">
You could try something like following:
function PickTwoHighestCtrl() {
let els = document.querySelectorAll(".compulsory1");
let values = Array.prototype.map.call(els, (el) => {
return Number(el.value) || 0;
});
let highest = Math.max.apply(Math, values);
let secondHighest = Math.max.apply(
Math, values.filter(e => e !== highest)
);
console.log("Two highest values are:", highest, secondHighest, "and their sum is", highest + secondHighest)
}
document.addEventListener("DOMContentLoaded", PickTwoHighestCtrl);
<input class="compulsory1" type="text" value="1" />
<input class="compulsory1" type="text" value="3" />
<input class="compulsory1" type="text" value="2" />
Check this fiddle
<html>
<head>
<script>
var tdsCompulsory = document.getElementsByClassName('compulsory1');
var cDatax = [];
sum = 0;
for(var i = 0; i < 3; i++){
cDatax.push(tdsCompulsory[i].value);
}
// let's convert it to a real array of numbers, not of strings :
var intArray = cDatax.map(Number);
var max = Math.max.apply(null, intArray);
// now let's sort it and take the second element :
var second = intArray.sort(function(a,b){return b-a})[1];
var sum = max+second;
alert(sum)
</script>
</head>
<body>
<table id="tableID">
<tr>
<td> <input name="name" class="compulsory1" type="text" value="1" /> </td>
<td> <input name="name1" class="compulsory1" type="text" value="3" /> </td>
<td> <input name="name2" class="compulsory1" type="text" value="2" /> </td>
<td>
</td>
</tr>
</table>
</body>
</html>
You can try something like this:
Steps
Get all elements
Get their values. Note, since you expect values to be number, yuo should parse them as well.
Sort value array in descending order instead of .sort + .reverse
Calculate your sum
Sample
// Get all elements
var tdsCompulsory = document.getElementsByClassName('compulsory1');
// Get values from all elements
var valArr = Array.prototype.map.call(tdsCompulsory, function(el) {
return parseInt(el.value)
});
// Sort value array in descending order
var cDatax = valArr.sort(function(a, b) {
return b-a
});
var sum = cDatax[0] + cDatax[1];
console.log(sum)
<table id="tableID">
<tr>
<td>
<input name="name" class="compulsory1" type="text" value="1" />
</td>
<td>
<input name="name1" class="compulsory1" type="text" value="3" />
</td>
<td>
<input name="name2" class="compulsory1" type="text" value="2" />
</td>
</tr>
</table>
var tdsCompulsory = document.getElementsByClassName('compulsory1'),
cDatax = Array.prototype.map.call(tdsCompulsory, function(el) {
return parseInt(el.value) || 0;
}),
sum = 0;
cDatax
.sort(function(a, b){
return a - b;
})
.reverse();
sum = cDatax[0] + cDatax[1];
console.log(sum);
<table id="tableID">
<tr>
<td><input name="name" class="compulsory1" type="text" value="1" /></td>
<td><input name="name1" class="compulsory1" type="text" value="3" /></td>
<td><input name="name2" class="compulsory1" type="text" value="2" /></td>
</tr>
</table>
I am adding rows using java script functions by taking input and showing data into input text fields.
I am using this datepicker https://github.com/T00rk/bootstrap-material-datetimepicker.
When I input time the only first value of time is copied into input fields while rest two value are copied but time value is not copied.
<div style="width:90%;margin:auto;">
<h1>Simple example of dynamically adding rows with jQuery</h1>
<form method="post">
<div id="itemRows">
Item quantity: <input type="text" name="add_qty" size="4" /> Item name: <input type="text" name="add_name" />Time:<input type="text" id="time" name="time" />
(This row will not be saved unless you click on "Add row" first)
<input onclick="addRow(this.form);" type="button" value="Add row" />
</div>
<p><input type="submit" name="ok" value="Save Changes"></p>
</form>
<script type="text/javascript">
var rowNum = 0;
function addRow(frm) {
rowNum ++;
var row = '<p id="rowNum'+rowNum+'">Item quantity: <input type="text" name="qty[]" size="4" value="'+frm.add_qty.value+'">Time<input type="text" id="time" name="time[]" size="4" value="'+frm.time.value+'" > Item name: <input type="text" name="name[]" value="'+frm.add_name.value+'"><input type="button" value="Remove" onclick="removeRow('+rowNum+');"></p>';
jQuery('#itemRows').append(row);
frm.add_qty.value = '';
frm.add_name.value = '';
frm.time.value = '';
}
function removeRow(rnum) {
jQuery('#rowNum'+rnum).remove();
}
</script>
When you generate dynamic textbox with id and with date picker so you need to call one function for init datepicker on that text like below
$('input').bootstrapMaterialDatePicker();
function addRow(frm)
{
rowNum ++;
var row = '<p id="rowNum'+rowNum+'">Item quantity: <input type="text" name="qty[]" size="4" value="'+frm.add_qty.value+'">Time<input type="text" id="time'+rowNum+'" name="time[]" size="4" value="'+frm.time.value+'" > Item name: <input type="text" name="name[]" value="'+frm.add_name.value+'"><input type="button" value="Remove" onclick="removeRow('+rowNum+');"></p>';
jQuery('#itemRows').append(row);
frm.add_qty.value = '';
frm.add_name.value = '';
frm.time.value = '';
$('#time'+rowNum).bootstrapMaterialDatePicker();
}
In above function i add one id to time textbox and call bootstrap datepicker to init date on that textbox.
See working demo here
http://plnkr.co/edit/P0ZQsAjDJAXyJGs9kvT3?p=preview
I am having table below.. but Getting wrong calculation in javascript..
<script>
function getPrice(tRate, tMaking, tHandeling, tPrice, tVat, tQuantity, tTotal) {
var obj_tRate = document.getElementById(tRate)
var obj_tMaking = document.getElementById(tMaking)
var obj_tHandeling = document.getElementById(tHandeling)
var obj_tPrice = document.getElementById(tPrice)
var obj_tVat = document.getElementById(tVat)
var obj_tTotal = document.getElementById(tTotal)
var obj_tQuantity = document.getElementById(tQuantity)
if (obj_tRate.value != "" && obj_tMaking.value != "" && obj_tHandeling.value != "") {
obj_tPrice.value = parseFloat(obj_tRate.value) + parseFloat(obj_tMaking.value) + parseFloat(obj_tHandeling.value);
console.log(obj_tPrice.value)
obj_tVat.value = parseFloat(obj_tPrice.value * (1 / 100));
console.log(obj_tVat.value)
obj_tTotal.value = parseFloat(obj_tVat.value + (obj_tPrice.value * obj_tQuantity.value));
console.log(obj_tTotal.value)
}
else {
obj_tPrice.value = "";
}
}
</script>
</head>
<body>
<table>
<tr>
<td>
<input name="grdView$ctl08$txtWaight_F" type="text" id="grdView_ctl08_txtWaight_F" class="classWaight" style="width:60px;" />
</td><td>
<input name="grdView$ctl08$txtQuantity_F" type="text" maxlength="20" id="grdView_ctl08_txtQuantity_F" class="classQuantity" onchange="javascript:return getPrice('grdView_ctl08_txtRate_F','grdView_ctl08_txtMaking_F','grdView_ctl08_txtHandeling_F','grdView_ctl08_txtPrice_F','grdView_ctl08_txtvat_F','grdView_ctl08_txtQuantity_F','grdView_ctl08_txtTotal_F');" style="width:60px;" />
</td><td>
<input name="grdView$ctl08$txtRate_F" type="text" maxlength="8" id="grdView_ctl08_txtRate_F" class="classRate" onchange="javascript:return getPrice('grdView_ctl08_txtRate_F','grdView_ctl08_txtMaking_F','grdView_ctl08_txtHandeling_F','grdView_ctl08_txtPrice_F','grdView_ctl08_txtvat_F','grdView_ctl08_txtQuantity_F','grdView_ctl08_txtTotal_F');" style="width:60px;" />
</td><td>
<input name="grdView$ctl08$txtMaking_F" type="text" id="grdView_ctl08_txtMaking_F" class="classMaking" onchange="javascript:return getPrice('grdView_ctl08_txtRate_F','grdView_ctl08_txtMaking_F','grdView_ctl08_txtHandeling_F','grdView_ctl08_txtPrice_F','grdView_ctl08_txtvat_F','grdView_ctl08_txtQuantity_F','grdView_ctl08_txtTotal_F');" style="width:60px;" />
</td><td>
<input name="grdView$ctl08$txtHandeling_F" type="text" id="grdView_ctl08_txtHandeling_F" class="classHandling" onchange="javascript:return getPrice('grdView_ctl08_txtRate_F','grdView_ctl08_txtMaking_F','grdView_ctl08_txtHandeling_F','grdView_ctl08_txtPrice_F','grdView_ctl08_txtvat_F','grdView_ctl08_txtQuantity_F','grdView_ctl08_txtTotal_F');" style="width:60px;" />
</td><td>
<input name="grdView$ctl08$txtPrice_F" type="text" id="grdView_ctl08_txtPrice_F" class="classPrice" style="width:60px;" />
</td><td>
<input name="grdView$ctl08$txtvat_F" type="text" id="grdView_ctl08_txtvat_F" class="classVat" style="width:60px;" />
</td><td>
<input name="grdView$ctl08$txtTotal_F" type="text" id="grdView_ctl08_txtTotal_F" class="classTotal" style="width:100px;" />
</td><td>
<input name="grdView$ctl08$txtSerial_F" type="text" id="grdView_ctl08_txtSerial_F" class="classSerial" />
</td>
</tr>
</table>
</body>
Use parseFloat on the operands, not on the result of the computation.
For example, replace
obj_tTotal.value = parseFloat(obj_tVat.value + (obj_tPrice.value * obj_tQuantity.value));
with
var tPrice = parseFloat(obj_tPrice.value);
var tQuantity = parseFloat(obj_tQuantity.value);
obj_tTotal.value = tPrice + tPrice * tQuantity;
When you add, like you did, a string and a number, you do a string concatenation.
For example
"1000" + "5" * "100"
gives
"1000" + 500
which is
"1000500"
At this point, it's too late to call parseFloat.
I searched a lot for this, but I can only find +1 -1 solutions.
But I want to set the number of inputs with a other input like this:
//Enter the number of inputs (1 is the start-value)
<input type="text" size="3" maxlength="3" id="count" name="count" value="1">
//Display that number of inputs (1 at start)
<input type="text" size="30" maxlength="30" id="input_1" name="input_1">
When the user now writes 5 in the first field, the form should look like this:
//Enter the number of inputs (1 is the start-value)
<input type="text" size="3" maxlength="3" id="count" name="count" value="1">
//Display that number of inputs (1 at start)
<input type="text" size="30" maxlength="30" id="input_1" name="input_1">
<input type="text" size="30" maxlength="30" id="input_2" name="input_2">
<input type="text" size="30" maxlength="30" id="input_3" name="input_3">
<input type="text" size="30" maxlength="30" id="input_4" name="input_4">
<input type="text" size="30" maxlength="30" id="input_5" name="input_5">
How can I make this? MUST I use js?
Here's a simple javascript snippet that doesn't make use of any frameworks:
function addInputs() {
var count = parseInt(document.getElementById("count").value);
for (var i = 2; i <= count; i++) {
document.getElementById('moreinputs').innerHTML += '<input type="text" name="input_' + i + '" id="input_' + i + '" />';
}
}
In this example you have to add a container (div) with id 'moreinputs'. However, when calling this function more than once, it will not work properly (e.g. it can only increase the number of input but not decrease)
Yes, either you use javascript, or you send the form to the server, where a new html page with all the inputs is generated (e.g. with PHP).
Yes you must use js to do it dynamically on the spot You have a jQuery tag so I will show an example in jQuery
This is not the best example but it works and it's a starting point
JS:
$(function(){
$('#master').on('change', function() {
var count = $(this).val();
$('#otherInputs').html('')
for( var i = 0; i < count; i++) {
$('#otherInputs').append(
$('<input>', {type: 'text'})
);
}
});
});
HTML:
<input type="number" id="master" value="1">
<div id="otherInputs"></div>
Demo
In English this is saying...
When you change #master I will empty #master (html('')) loop through and append a new input depending on #master's value
Here's the FIDDLE. Hope it helps. :)
html
<input type="text" size="3" maxlength="3" id="count" name="count" value="1">
<div id="container"></div>
script
$('#count').on('keyup', function () {
var $this = $(this);
var count = $this.val();
$('#container').empty();
for (var x = 1; x <= count; x++) {
var newInput = '<input type="text" size="30" maxlength="30" id="input_' + x + '" name="input_' + x + '">';
$('#container').append(newInput);
}
});
This worked for me
function AddField() {
var count = $("#countetfield").val();
var i = 1;
var id = $("#container .testClass:last").attr('name');
var test = id.split("_");
id_name = test[1];
while (i <= count) {
id_name++;
var a = '<input type="text" class="testClass" size="30" maxlength="30" id="input_' + id_name + '" name="input_' + id_name + '"/>';
$("#container").append(a);
i++;
}
}
<input type="text" id="countetfield" value="1" />
<input type="button" value="Go" onclick="AddField();" />
<div id="container">
<input type="text" class="testClass" size="30" maxlength="30" id="input_1" name="input_1" />
</div>
I have a script that calculates the values in each and shows the calulated values. At the end it also calculates the already calculated values from all div's
Here is the html code:
<td>
<div>
<input name="r" class="rate" type="text" maxlength="255" size="5" value />
<input name="p" class="pack" type="text" maxlength="255" size="5" value />
<span class="amount"></span>
</div>
</td>
<td>
<div>
<input name="r" class="rate" type="text" maxlength="255" size="5" value />
<input name="p" class="pack" type="text" maxlength="255" size="5" value />
<span class="amount"></span>
</div>
</td>
The problem is that I want to put all fields in a form and then submit them to a database.
However, all divs contain two input fields with name "r" and "p".
So, I am kind of stuck here because I cannot figure out how to make the names unique or how to have them passed to the DB using POST.
This is what the calculating script looks like:
<script type="text/javascript">//<![CDATA[
//any time the amount changes
$(document).ready(function() {
$('input[name=r],input[name=p]').change(function(e) {
var total = 0;
var $row = $(this).parent();
var rate = $row.find('input[name=r]').val();
var pack = $row.find('input[name=p]').val();
total = parseFloat(rate * pack);
//update the row total
$row.find('.amount').text(total);
var total_amount = 0;
$('.amount').each(function() {
//Get the value
var am= $(this).text();
console.log(am);
//if it's a number add it to the total
if (IsNumeric(am)) {
total_amount += parseFloat(am, 10);
}
});
$('.total_amount').text(total_amount);
});
});
//isNumeric function Stolen from:
//http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
function IsNumeric(input) {
return (input - 0) == input && input.length > 0;
}
//]]>
</script>
HTML:
<input type="text" name="r[]">
<input type="text" name="p[]">
<hr>
<input type="text" name="r[]">
<input type="text" name="p[]">
<hr>
<input type="text" name="r[]">
<input type="text" name="p[]">
PHP:
for ($i = 0; $i < count($_POST['p']); $i++) {
$rate = $_POST['r'][$i];
$pack = $_POST['p'][$i];
// do something with $rate and $pack
}
Since the browser submits all inputs (even if no value has been entered) and by specification it submits them in the order they are defined in the HTML code, you can rely that the elements in the two $_POST arrays will line up and the corresponding rate and pack will be received at the same index in the respective array.