I am new to JavaScript.
Current issues I'm facing:
- When you add a new row it's adding the row (great!) however the first new one added works fine, applies _0 at the end of the name / id however when you add more it does not do _1, _2 etc.. but instead _1_1, _2_2_2, _3_3_3_3 - any ideas how I can fix that?
- I need to calculate the sub total and totals from figures added on the invoice items, like price, qty, discount (figure or %) sub-total and then overall from everything at bottom. The VAT is set as a variable in PHP at the moment for example define('VAT_RATE','20') which would be 20%
UPDATE
I have attempted to start it, getting NaN though and its only taking anything with a class="calculate" and adding to sub-total but it's a start I guess. I added qty but does not seem to play ball, vat and total I have not added.
JSFiddle: /
JS:
$(document).ready(function () {
// copy customer details to shipping
$('input.copy-input').on("change keyup paste", function () {
var thisID = $(this).attr('id');
$('input#' + thisID + "_ship").val($(this).val());
});
// add new product row on invoice
$(".add-row").click(function () {
$("#invoice_table").each(function () {
var tds = '<tr>';
jQuery.each($('tr:last td', this), function (index, element) {
var html = $(this).html().replace(/invoice_product/g, 'invoice_product_' + index)
.replace(/invoice_product_desc/g, 'invoice_product_desc_' + index)
.replace(/invoice_product_qty/g, 'invoice_product_qty_' + index)
.replace(/invoice_product_price/g, 'invoice_product_price_' + index)
.replace(/invoice_product_sub/g, 'invoice_product_sub_' + index);
tds += '<td>' + html + '</td>';
});
tds += '</tr>';
if ($('tbody', this).length > 0) {
$('tbody', this).append(tds);
} else {
$(this).append(tds);
}
});
return false
});
// Adding the change events for the Price and
// quantity fields only..
// Changing the total should not affect anything
calculateTotal();
$('.calculate').on('change keyup paste', function() {
updateTotals(this);
calculateTotal();
});
function updateTotals(elem) {
// This will give the tr of the Element Which was changed
var $container = $(elem).parent().parent();
var quantity = $container.find('.calculate-qty').val();
var price = $container.find('.calculate').val();
var subtotal = parseInt(quantity) * parseFloat(price);
$container.find('.calculate-sub').text(subtotal.toFixed(2));
}
function calculateTotal(){
// This will Itearate thru the subtotals and
// claculate the grandTotal and Quantity here
var lineTotals = $('.calculate-sub');
var grandTotal = 0.0;
var totalQuantity = 0;
$.each(lineTotals, function(i){
grandTotal += parseFloat($(lineTotals[i]).text()) ;
});
$('.invoice-sub-total').text(parseFloat(grandTotal ).toFixed(2) );
}
});
I am new to JavaScript.
Current issues I'm facing:
- When you add a new row it's adding the row (great!) however the first new one added works fine, applies _0 at the end of the name / id however when you add more it does not do _1, _2 etc.. but instead _1_1, _2_2_2, _3_3_3_3 - any ideas how I can fix that?
- I need to calculate the sub total and totals from figures added on the invoice items, like price, qty, discount (figure or %) sub-total and then overall from everything at bottom. The VAT is set as a variable in PHP at the moment for example define('VAT_RATE','20') which would be 20%
UPDATE
I have attempted to start it, getting NaN though and its only taking anything with a class="calculate" and adding to sub-total but it's a start I guess. I added qty but does not seem to play ball, vat and total I have not added.
JSFiddle: http://jsfiddle/morgjvg6/4/
JS:
$(document).ready(function () {
// copy customer details to shipping
$('input.copy-input').on("change keyup paste", function () {
var thisID = $(this).attr('id');
$('input#' + thisID + "_ship").val($(this).val());
});
// add new product row on invoice
$(".add-row").click(function () {
$("#invoice_table").each(function () {
var tds = '<tr>';
jQuery.each($('tr:last td', this), function (index, element) {
var html = $(this).html().replace(/invoice_product/g, 'invoice_product_' + index)
.replace(/invoice_product_desc/g, 'invoice_product_desc_' + index)
.replace(/invoice_product_qty/g, 'invoice_product_qty_' + index)
.replace(/invoice_product_price/g, 'invoice_product_price_' + index)
.replace(/invoice_product_sub/g, 'invoice_product_sub_' + index);
tds += '<td>' + html + '</td>';
});
tds += '</tr>';
if ($('tbody', this).length > 0) {
$('tbody', this).append(tds);
} else {
$(this).append(tds);
}
});
return false
});
// Adding the change events for the Price and
// quantity fields only..
// Changing the total should not affect anything
calculateTotal();
$('.calculate').on('change keyup paste', function() {
updateTotals(this);
calculateTotal();
});
function updateTotals(elem) {
// This will give the tr of the Element Which was changed
var $container = $(elem).parent().parent();
var quantity = $container.find('.calculate-qty').val();
var price = $container.find('.calculate').val();
var subtotal = parseInt(quantity) * parseFloat(price);
$container.find('.calculate-sub').text(subtotal.toFixed(2));
}
function calculateTotal(){
// This will Itearate thru the subtotals and
// claculate the grandTotal and Quantity here
var lineTotals = $('.calculate-sub');
var grandTotal = 0.0;
var totalQuantity = 0;
$.each(lineTotals, function(i){
grandTotal += parseFloat($(lineTotals[i]).text()) ;
});
$('.invoice-sub-total').text(parseFloat(grandTotal ).toFixed(2) );
}
});
Share
Improve this question
edited Feb 11, 2018 at 11:30
halfer
20.4k19 gold badges109 silver badges202 bronze badges
asked May 3, 2015 at 11:59
JamesJames
1,7061 gold badge21 silver badges54 bronze badges
11
- here is the answer to your first question: JSfiddle. Is that what you need? – viral Commented May 3, 2015 at 12:58
- Yep almost! the numbering is working great but its updating them all as invoice_product_1 for each and every name / id and replacing others like invoice_product_desc - so not doing for them all but replacing them all with same name if that makes sense. Thanks for your help, any ideas how to fix that? – James Commented May 3, 2015 at 13:07
- Any ideas? sorry to be a pain on a right deadline :) – James Commented May 3, 2015 at 13:50
-
can you change
flag
toindex
in your regex, and see if it does the job ? – viral Commented May 3, 2015 at 13:56 - 1 sec, will try that now. thanks mate – James Commented May 3, 2015 at 13:57
1 Answer
Reset to default 5First, you have to use event delegation for input fields that were created dynamically:
// delegate events on #invoice_table:
$('#invoice_table').on('change keyup paste', '.calculate', function() {
updateTotals(this);
calculateTotal();
});
Next thing is that you used .text()
to update input field:
$container.find('.calculate-sub').text(subtotal.toFixed(2));
while you should use .val()
:
$container.find('.calculate-sub').val(subtotal.toFixed(2));
The same in calculateTotal()
method, where you should also use .val()
.
Next, this part is unnecesary :
$("#invoice_table").each(function () {
since you have only one table (and only one element in DOM can have that id
).
Finaly, I would not use id
attributes, and give array names for input fields. That way you don't have to play with .replace()
and you can easily send all the values to your back-end app as arrays.
Also, I'd clone()
the whole tr
element initially and use it later on, instead of setting loops for each click.
// copy customer details to shipping
$('input.copy-input').on("change keyup paste", function () {
$('input#' + this.id + "_ship").val($(this).val());
});
// add new product row on invoice
var cloned = $('#invoice_table tr:last').clone();
$(".add-row").click(function (e) {
e.preventDefault();
cloned.clone().appendTo('#invoice_table');
});
calculateTotal();
$('#invoice_table').on('change keyup paste', '.calculate', function() {
updateTotals(this);
calculateTotal();
});
function updateTotals(elem) {
var tr = $(elem).closest('tr'),
quantity = $('[name="invoice_product_qty[]"]', tr).val(),
price = $('[name="invoice_product_price[]"]', tr).val(),
percent = $('[name="invoice_product_discount[]"]', tr).val(),
subtotal = parseInt(quantity) * parseFloat(price);
// CALCULATE DISCOUNT PERCENTAGE:
if(percent && $.isNumeric(percent) && percent !== 0){
subtotal = subtotal - ((parseInt(percent) / 100) * subtotal);
}
$('.calculate-sub', tr).val(subtotal.toFixed(2));
}
function calculateTotal(){
var grandTotal = 0.0;
var totalQuantity = 0;
$('.calculate-sub').each(function(){
grandTotal += parseFloat($(this).val()) ;
});
$('.invoice-sub-total').text(parseFloat(grandTotal ).toFixed(2) );
}
JSFiddle (Note, I have removed id
attributes and added []
to the input fields names)
An example of how you could retrieve values sent to PHP
(Each iteration inside loop will be analogue to each tr
):
foreach($_POST['invoice_product'] as $key => $value){
$name = $value;
$qty = $_POST['invoice_product_qty'][$key];
$price = $_POST['invoice_product_price'][$key];
$discount = $_POST['invoice_product_discount'][$key];
// ...
}