jquery to sum two inputs on dynamic table and display in third - javascript

With the SO community I have got a script that adds rows with unique names to a table. I want to take two inputs on each row and multiply them together and display result in a third input.
the fiddle is at http://jsfiddle.net/yUfhL/231/
My code is:
HTML
<table class="order-list">
<tr><td>Product</td><td>Price</td><td>Qty</td><td>Total</td></tr>
<tr>
<td><input type="text" name="product" /></td>
<td><input type="text" name="price" /></td>
<td><input type="text" name="qty" /></td>
<td><input type="text" name="linetotal" /></td>
</tr>
</table>
<div id="grandtotal">
Grand Total Here
</div>
JS
var counter = 1;
jQuery("table.order-list").on('change','input[name^="product"]',function(event){
event.preventDefault();
counter++;
var newRow = jQuery('<tr><td><input type="text" name="product' +
counter + '"/></td><td><input type="text" name="price' +
counter + '"/></td><td><input type="text" name="qty' +
counter + '"/></td><td><input type="text" name="total' +
counter + '"/></td><td><a class="deleteRow"> x </a></td></tr>');
jQuery('table.order-list').append(newRow);
});
jQuery("table.order-list").on('click','.deleteRow',function(event){
$(this).closest('tr').remove();
});
$('table.order-list tr').each(function() {
var price = parseInt( $('input[id^=price]', this).val(), 10 );
var qty = parseInt( $('input[id^=qty]' , this).val(), 10 );
$('input[id^=linetotal]', this).val(price * qty);
});
So currently I cant get the js to fire that gets the product of the two cells, qty and price. I want to display result in linetotal.
The last part of this would be to display the sum of all linetotals as a grand total in the div grandtotal
Help appreciated as always.

You're only giving the elements a name attribute, but using the id selector ([id^=price]). It's much easier to give them a specific class than having to use that "id starts with" selector. Also, when do you want the line totals to be calculated? And when do you want the grand total to be calculated? On what event(s)?
Here's my interpretation of how it should look:
<table class="order-list">
<thead>
<tr><td>Product</td><td>Price</td><td>Qty</td><td>Total</td></tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="product" /></td>
<td>$<input type="text" name="price" /></td>
<td><input type="text" name="qty" /></td>
<td>$<input type="text" name="linetotal" readonly="readonly" /></td>
<td><a class="deleteRow"> x </a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: center;">
<input type="button" id="addrow" value="Add Product" />
</td>
</tr>
<tr>
<td colspan="5">
Grand Total: $<span id="grandtotal"></span>
</td>
</tr>
</tfoot>
</table>
And the JS:
$(document).ready(function () {
var counter = 1;
$("#addrow").on("click", function () {
counter++;
var newRow = $("<tr>");
var cols = "";
cols += '<td><input type="text" name="product' + counter + '"/></td>';
cols += '<td>$<input type="text" name="price' + counter + '"/></td>';
cols += '<td><input type="text" name="qty' + counter + '"/></td>';
cols += '<td>$<input type="text" name="linetotal' + counter + '" readonly="readonly"/></td>';
cols += '<td><a class="deleteRow"> x </a></td>';
newRow.append(cols);
$("table.order-list").append(newRow);
});
$("table.order-list").on("change", 'input[name^="price"], input[name^="qty"]', function (event) {
calculateRow($(this).closest("tr"));
calculateGrandTotal();
});
$("table.order-list").on("click", "a.deleteRow", function (event) {
$(this).closest("tr").remove();
calculateGrandTotal();
});
});
function calculateRow(row) {
var price = +row.find('input[name^="price"]').val();
var qty = +row.find('input[name^="qty"]').val();
row.find('input[name^="linetotal"]').val((price * qty).toFixed(2));
}
function calculateGrandTotal() {
var grandTotal = 0;
$("table.order-list").find('input[name^="linetotal"]').each(function () {
grandTotal += +$(this).val();
});
$("#grandtotal").text(grandTotal.toFixed(2));
}
http://jsfiddle.net/QAa35/
In your JS, you weren't using linetotal for the one dynamic input's name. There were other several minor modifications I made. You might as well use <thead>, <tbody> and <tfoot> since you do have those sections in the <table>. Also, I don't think it's a good design to have a new row automatically added when the "product" inputs are changed. That can happen often, and their intent may not be to add a new product...a button is much more friendly. For example, say you type in "asdf" to the first "product" input, then click somewhere. A new row is added. Say you made a typo so you go back and change it to "asd", then click somewhere. Another new row is added. That doesn't seem right.

This function should do the trick:
function updateGrandTotal() {
var prices = [];
$('input[name^="price"]').each(function () {
prices.push($(this).val());
});
var qnts = [];
$('input[name^="qty"]').each(function () {
qnts.push($(this).val());
});
var total = 0;
for(var i = 0; i < prices.length; i++){
total += prices[i] * qnts[i];
}
$('#grandtotal').text(total.toFixed(2));
}
You just need to bind it to the table change event to update the grand total every time an input changes:
$("table.order-list").change(updateGrandTotal);
Here is a working fiddle.

Related

Calculate total of each added row separately and total of all rows in Javascript

I am new in javascript and facing a problem. I have invoice rows which can be added by pressing on a button. Now i want to calculate the total amount for each row separately(for which the formula is (quantity * price). And the total of all rows combined should become the total of the invoice. The problem is that when I enter the price and quantity in first row, it calculates the total but when I add a new row, it does not calculate the total for new added row after entering the value. Kindly help me in this regard.
function myFunction() {
var x = document.getElementById("price").value;
var y = document.getElementById("quantity").value;
if (x != "") {
document.getElementById("total").value = x * y;
}
}
function add_fields() {
var tableid = document.getElementById('product_table');
var row = document.createElement("tr");
row.innerHTML =
'<td><input type="text" name="price" id="price" oninput="myFunction()"> </td>' +
'<td><input type="text" name="quantity" id="quantity" oninput = "myFunction()" > < /td>' +
'<td><input type="text" name="total" id="total" readonly></td>';
tableid.appendChild(row);
}
table,
tr,
td,
th {
border: 1px black solid;
}
<table>
<thead>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
</thead>
<tbody id="product_table">
<tr>
<td><input type="text" name="price" id="price" oninput="myFunction();"></td>
<td><input type="text" name="quantity" id="quantity" oninput="myFunction();"></td>
<td><input type="text" name="total" id="total" readonly></td>
</tr>
</tbody>
<input type="button" name="submit" value="Add Row" onclick="add_fields();">
Use event delegation instead - add a single listener to the container, listen for input events. Then, from the target property of the event, you can get the changed input element. Use .closest to get to the parent <tr>, and then from its descendants, you can get to the associated price, quantity, and total <input>s, and assign values appropriately.
Note that this adds the handler using Javascript, rather than with inline HTML attributes, which are generally considered to be pretty poor practice and can be difficult to manage. Also, duplicate IDs in a single document is invalid HTML - IDs aren't needed anyway here, because the inputs you want are always in a predictable order inside each <tr>. So, you can remove the id and the onclick attributes from the HTML and from the row.innerHTML string:
const table = document.getElementById('product_table');
table.addEventListener('input', ({ target }) => {
const tr = target.closest('tr');
const [price, quantity, total] = tr.querySelectorAll('input');
total.value = price.value * quantity.value;
});
function add_fields() {
var row = document.createElement("tr");
row.innerHTML =
'<td><input type="text" name="price"> </td > ' +
'<td><input type="text" name="quantity"> </td>' +
'<td><input type="text" name="total" readonly></td>';
table.appendChild(row);
}
table,
tr,
td,
th {
border: 1px black solid;
}
<table>
<thead>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
</thead>
<tbody id="product_table">
<tr>
<td><input type="text" name="price"></td>
<td><input type="text" name="quantity"></td>
<td><input type="text" name="total" readonly></td>
</tr>
</tbody>
<input type="button" name="submit" value="Add Row" onclick="add_fields();">

How to save table content permanently

I am an absolute beginner in javascript. I tried to make an table which can save the content i type in it. I just got the total opposite from what i wanted the table deletes the content everytime i refresh the website.
Basically my question is what i have to change so i can save the data permantly and it dont vanish everytime i refresh the webpage. Also it would nice to know what i did wrong. I already tried to change some things but it got just worse
Here is some example code for you:
JS:
$(document).ready(function () {
var counter = 0;
$("#addrow").on("click", function () {
var newRow = $("<tr>");
var cols = "";
cols += '<td><input type="text" class="form-control" name="name' + counter + '"/></td>';
cols += '<td><input type="text" class="form-control" name="mail' + counter + '"/></td>';
cols += '<td><input type="text" class="form-control" name="phone' + counter + '"/></td>';
cols += '<td><input type="button" class="ibtnDel btn btn-md btn-danger " value="Delete"></td>';
newRow.append(cols);
$("table.order-list").append(newRow);
counter++;
});
$("table.order-list").on("click", ".ibtnDel", function (event) {
$(this).closest("tr").remove();
counter -= 1
});
});
function calculateRow(row) {
var price = +row.find('input[name^="price"]').val();
}
function calculateGrandTotal() {
var grandTotal = 0;
$("table.order-list").find('input[name^="price"]').each(function () {
grandTotal += +$(this).val();
});
$("#grandtotal").text(grandTotal.toFixed(2));
}
Basic HTML:
<div class="container">
<table id="myTable" class=" table order-list">
<thead>
<tr>
<td>name</td>
<td>mail</td>
<td>phone</td>
</tr>
</thead>
<tbody>
<tr>
<td class="col-sm-4">
<input type="text" name="name" class="form-control" />
</td>
<td class="col-sm-4">
<input type="mail" name="mail" class="form-control"/>
</td>
<td class="col-sm-3">
<input type="text" name="phone" class="form-control"/>
</td>
<td class="col-sm-2"><a class="deleteRow"></a>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: left;">
<input type="button" class="btn btn-lg btn-block " id="addrow" value="Add Row" />
</td>
</tr>
<tr>
</tr>
</tfoot>
You can use the localStorage object, which stores data with no expiration date. This data will not be deleted when you refresh the page or even close the browser.
In order to do that, you first need to create the function which will save the data into localStorage.
function save_data(){
let table_data = []
$('.form-control').each(function() { table_data.push( $(this).val() )});
localStorage.setItem('table_data', JSON.stringify(table_data));
}
This function iterates through all table cells and saves its content into table_data array.
Then table_data array is converted into String with JSON.stringify and saved in localStorage.
This function should be executed every time you add, remove or edit one of the rows.
In order to do that we need to create new event handlers:
$('tbody').on("DOMSubtreeModified", function() {save_data()});
$('tbody').on('change', '.form-control', function() {save_data()});
The first one triggers save_data function every time a row is created or removed.
The second one saves data whenever the table's content is modified.
We also need a function for loading data from localStorage:
function load_data(){
let table_data = JSON.parse(localStorage.getItem('table_data'));
for (i = 1; i < table_data.length/3; i++) $("#addrow").click()
$('.form-control').each(function(index) {$(this).val(table_data[index])});
}
This function loads data from localStorage using getItem function.
The loaded data is a String, so it is converted into the array using JSON.parse.
Next, new rows are inserted according to the size of table_data array.
In the end, it iterates through all table cells and fills them with loaded data.
This function should be executed only after you the page is loaded and only if data exists in localStorage.The best way is to put this line at the bottom of ready function:
if (localStorage.getItem("table_data") != null) load_data()

How to set name value of dynamic adding input ? javascript jquery

I have a web page for applying. In this web page, rows are dynamic add after addp button clicked.I can add new row successfully with addPf() method. And these input name attribute should be enName0, enName1, enName2....., but it works fail with name="enName"+aDWI.
Here is my html code:
<div>
<table>
<tr>
<td>
<input type="button" id="addP" onclick="addPf()" value="addPeople">
</td>
</tr>
<tr>
<td>
new row added in here;
</td>
</tr>
</table>
</div>
Here is my javascript code:
<script>
var aDWI=0;
function addPf()
{
newrow = '<tr><td><input style="width:98%" name="enName"+aDWI></td></tr>';
$(newrow).insertAfter($('#staTable tr:eq('+aDWI+')'));
aDWI = aDWI + 1;
}
</script>
name="enName"+aDWI is not right.I have no idea about this, who can help me ?
Change from
newrow = '<tr><td><input style="width:98%" name="enName"+aDWI></td></tr>';
to
newrow = '<tr><td><input style="width:98%" name="enName'+aDWI+'"></td></tr>';
The issue is because you need to concatenate the variable in the string correctly, using the ' character.
Also note that you should really be using unobtrusive event handlers instead of the outdated on* event attributes. In addition, you can simplify the logic by using jQuery's append(), like this:
var aDWI = 0;
$('#addP').click(function() {
newrow = '<tr><td><input style="width:98%" name="enName' + aDWI + '" value="' + aDWI + '"></td></tr>';
$('#staTable').append(newrow);
aDWI = aDWI + 1;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<table id="staTable">
<tr>
<td>
<input type="button" id="addP" value="addPeople">
</td>
</tr>
<tr>
<td>
new row added in here;
</td>
</tr>
</table>
</div>
Just update it with
<script>
var aDWI=0;
function addPf()
{
newrow = '<tr><td><input style="width:98%" name="enName'+aDWI+'"></td></tr>';
$(newrow).insertAfter($('#staTable tr:eq('+aDWI+')'));
aDWI = aDWI + 1;
}
</script>

reading dynamically added input values into an array php

Every thing is working expect that on adding the dynamic fields,the input added is not captured into the array.Only the values in the only created input are read. HTML PART
<table class="table table-bordered table-hover order-list" >
<thead>
<tr><td>Product</td><td>Price (Ksh.) </td><td>Qty</td><td> (Ksh.)</td></tr>
</thead>
<tbody>
<tr>
<td><input type="text" class="form-control" name="product[]" required="" /></td>
<td><input type="text" class="form-control" name="price[]" required/></td>
<td><input type="text" class="form-control" name="quantity[]" /></td>
<td><input type="text" name="linetotal[]" readonly="readonly" /></td>
<td><a class="deleteRow"> x </a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: center;">
<input type="button" id="addrow" value="Add Product" />
</td>
</tr>
<tr>
<td colspan="5">
Grand Total: Ksh.<input type="text" name="grandtotal" readonly="readonly" /><span id="grandtotal"></span>
</td>
</tr>
</tfoot>
</table>
THE javascript to sum up the get the sub total and grand total is as below:
$(document).ready(function () {
var counter = 1;
$("#addrow").on("click", function () {
counter++;
var newRow = $("<tr>");
var cols = "";
cols += '<td><input type="text" name="product' + counter + '"/></td>';
cols += '<td><input type="text" name="price' + counter + '"/></td>';
cols += '<td><input type="text" name="quantity' + counter + '"/></td>';
cols += '<td><input type="text" name="linetotal' + counter + '" readonly="readonly"/></td>';
cols += '<td><a class="deleteRow"> x </a></td>';
newRow.append(cols);
$("table.order-list").append(newRow);
});
$("table.order-list").on("change", 'input[name^="price"], input[name^="quantity"]', function (event) {
calculateRow($(this).closest("tr"));
calculateGrandTotal();
});
$("table.order-list").on("click", "a.deleteRow", function (event) {
$(this).closest("tr").remove();
calculateGrandTotal();
});
});
function calculateRow(row) {
var price = +row.find('input[name^="price"]').val();
var qty = +row.find('input[name^="quantity"]').val();
var linetotal = +row.find('input[name^="linetotal"]').val((price * qty).toFixed(2));
}
function calculateGrandTotal() {
var grandTotal = 0;
$("table.order-list").find('input[name^="linetotal"]').each(function () {
grandTotal += +$(this).val();
});
$("#grandtotal").text(grandTotal.toFixed(2));
}
the php part to read the array is
if(isset($_POST['cinvoice']) && $_SERVER["REQUEST_METHOD"] == "POST" &&is_array($_POST["product"]) && is_array($_POST["quantity"]) && is_array($_POST["price"]) && is_array($_POST["linetotal"]))
{
$recordid="";
$firstname="";
$product="";
$quantity="";
$price="";
$linetotal="";
foreach ($_POST["product"] as $key => $prod) {
$product .= $prod.",";
}
foreach ($_POST["quantity"] as $key => $qty){
$quantity.=$qty. ",";
}
foreach ($_POST["price"] as $key => $prc) {
$price.=$prc. ",";
}
foreach ($_POST["linetotal"] as $key => $linetotal) {
$linetotal.=$linetotal. ",";
}
you should pass textbox name as an array:
cols += '<td><input type="text" name="product[]"/></td>';
cols += '<td><input type="text" name="price[]"/></td>';
cols += '<td><input type="text" name="quantity[]"/></td>';
cols += '<td><input type="text" name="linetotal[]" readonly="readonly"/>
Also you can use implode function in php
foreach ($_POST["product"] as $key => $prod) {
$product .= $prod.",";
}
to
$product = implode(',', $_POST["product"])

Dynamically Added Rows and Calculation Function Error After First Row

I'm working a project, it is almost done but I got a problem to finish it. I tried a lot of things and searched on the web, but unfortunately I could not succeed it.
The problem is about dynamically added rows at the table. Auto-calculating script is just working on the first row of the table, at 2nd, 3rd, ... rows of the table it does not work.
jsFiddle for below the code:
<script type='text/javascript'>//<![CDATA[
$(window).load(function(){
$("#AddLine").click(function () {
//var row = "<tr><td><input type=text /></td><td><input type=text /></td><td><input type=text /></td><td><button>X</button></td></tr>";
var row = "<tr><td><input type=\"text\" style=\"width:100%;\" name=\"stokkodu[]\"></td><td><input type=\"text\" style=\"width:100%;\" name=\"stokadi[]\"></td><td><input type=\"text\" style=\"width:100%;\" id=\"miktar\" class=\"miktar\" name=\"miktar[]\"></td><td><input type=\"text\" style=\"width:100%;\" name=\"birim[]\"></td><td><input type=\"text\" style=\"width:100%;\" id=\"birimfiyat\" class=\"birimfiyat\" name=\"birimfiyat[]\"></td><td><input type=\"text\" style=\"width:100%;\" readonly id=\"tutar\" class=\"tutar\" name=\"tutar[]\"></td><td><input type=\"text\" style=\"width:100%;\" class=\"indirim\" name=\"indirim[]\"></td><td><input type=\"text\" style=\"width:100%;\" readonly class=\"indirimtutar\" name=\"indirimtutari[]\"></td><td><input type=\"text\" style=\"width:100%;\" class=\"kdv\" name=\"kdv[]\"></td><td><input type=\"text\" style=\"width:100%;\" readonly class=\"satirtoplami\" name=\"satirtoplami[]\"></td><td><button>X</button></td></tr>";
$("#table").append(row);
});
$("#table").on("click", "button", function() {
$(this).closest("tr").remove();
});
});
$(document).ready(function() {
$('input[id=miktar],input[id=birimfiyat],input[id=indirim],input[id=kdv], input[id=satirtoplami]').change(function(e) {
var total_mnozi = 0;
//var $row = $(this).parent();
var $row = $(this).closest("tr"); //this is the closest common root of the input elements
var miktar = parseFloat( $row.find('input[id=miktar]').val() );
var birimfiyat = parseFloat( $row.find('input[id=birimfiyat]').val() );
var indirim = parseFloat( $row.find('input[id=indirim]').val() );
var kdv = parseFloat( $row.find('input[id=kdv]').val() );
//total_mnozi = ((dep + minpre + adjpre) * procombase * profcomper) || 0; //calculate traditionally; display zero until result is meaningful
tutar = (miktar * birimfiyat) || 0; // tutar hesaplama. miktar x birim fiyat = tutar
indirimtutar= (tutar * indirim / 100) || 0; // indirim tutarı hesaplama input'a girilen %'ye göre hesaplar.
satirtoplami= ((tutar - indirimtutar) * ((kdv / 100) + 1 )) || 0;
$row.find('input[id=tutar]').val(tutar.toFixed(2)); // tutar'ın id="tutar"'a virgülden sonra 2 hane alacak şekilde yazdrılması.
$row.find('input[id=indirimtutar]').val(indirimtutar.toFixed(2));
$row.find('input[id=satirtoplami]').val(satirtoplami.toFixed(2));
});
});
//]]>
</script>
<input type="button" id="AddLine" value="add"/>
<table id="table">
<tr>
</tr>
<tr>
<td scope="col">Stok Kodu</th>
<td scope="col">Stok Adı</th>
<td scope="col">Miktar</th>
<td scope="col">Birim</th>
<td scope="col">Birim Fiyat</th>
<td scope="col">Tutar</th>
<td scope="col">İndirim (%)</th>
<td scope="col">İndirim Tutarı</th>
<td scope="col">KDV (%)</th>
<td scope="col">Satır Toplamı</th>
<td scope="col"></th>
</tr>
<tr>
<td><input type="text" style="width:100%;" name="stokkodu[]"></td>
<td><input type="text" style="width:100%;" name="stokadi[]"></td>
<td><input type="text" style="width:100%;" id="miktar" class="miktar" name="miktar[]"></td>
<td><input type="text" style="width:100%;" name="birim[]"></td>
<td><input type="text" style="width:100%;" id="birimfiyat" class="birimfiyat" name="birimfiyat[]"></td>
<td><input type="text" style="width:100%;" readonly id="tutar" class="tutar" name="tutar[]"></td>
<td><input type="text" style="width:100%;" id="indirim" class="indirim" name="indirim[]"></td>
<td><input type="text" style="width:100%;" readonly id="indirimtutar" class="indirimtutar" name="indirimtutari[]"></td>
<td><input type="text" style="width:100%;" id="kdv" class="kdv" name="kdv[]"></td>
<td><input type="text" style="width:100%;" readonly id="satirtoplami" class="satirtoplami" name="satirtoplami[]"></td>
<td><button>X</button></td>
</tr>
</table>​
How can I do this?
Your problem is with duplicate Ids.
You should not add two or more elements with the same Id. So, to solve the problem, your dynamically added elements should not have id attributes, then you use the class attribute to target the elements in each row.
Working sample: http://jsfiddle.net/3W48W/2/ (incorporating #Barmar 's answer)
HTM
There are two problems with your code:
First, you're using the same IDs in each row that you add dynamically. IDs are required to be unique.
Second, the .change() binding only applies to elements that are in the DOM at the time the page is loaded. To handle elements added dynamically, you need to use .on() to bind to a permanent element and delegate to the dynamic elements, or bind the event handler to the new row's elements after you append it to the DOM.

Categories