Skip to content
View in the app

A better way to browse. Learn more.

Web Designer Forum

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

JS Dynamic fields and adding calculations to them

Featured Replies

Hi there,

 

So the project is to create an invoicing tool.

 

I would like a bit of help to see how to go about this, i'm not good with javascript so you may have to bare with me.

 

So i currently have 1 row of 5 text inputs.

I can click a button to add another row (Maximum of 10 rows). Each row again has 5 text inputs.

 

So, i need to be able to add a calculation based on input.

 

Structure:

 

Item code > Item Name > Item price > Item quantity > Total

 

Id like Item Quantity to multiply with Item Price and give a total in the Total column and then take the Total columns that have data in them and add it all up for a sub total at the end.

 

Current code i have:

 

$(document).ready(function(){
 
    var counter = 2;
 
    $("#addButton").click(function () {
 
	if(counter>10){
            alert("Only 10 textboxes allowed");
            return false;
	}   
 
	var newTextBoxDiv = $(document.createElement('tr'))
	     .attr("id", 'TextBoxDiv' + counter);
 
	newTextBoxDiv.after().html('<td class="first" id="itmcode"><input placeholder="Insert Item ' + counter + '" class="itmcode" type="text" name="data[' + counter + 
	      '][0]" id="invitem' + counter + '" ></td>' + '<td id="itmnme"><input class="itmname" placeholder="Insert Item ' + counter + '" type="text" name="data[' + counter + 
	      '][1]" id="invitem' + counter + '" ></td>' + '<td id="itmdesc"><input class="itmdesc" placeholder="Insert Item ' + counter + '" type="text" name="data[' + counter + 
	      '][2]" id="invitem' + counter + '" ></td>' + '<td id="itmqty"><input class="itmamnt" id="itm-qty" placeholder="Insert Item ' + counter + '" type="text" name="data[' + counter + 
	      '][3]" id="invitem' + counter + '" ></td>' + '<td id="itmamnt"><input class="itmqty" id="itm-amnt" placeholder="Insert Item ' + counter + '" type="text" name="data[' + counter + 
	      '][4]" id="invitem' + counter + '" ></td>' + '<td><input type="text" name="total" id="total"/></td>');
 
	newTextBoxDiv.appendTo("#TextBoxesGroup");
 
 
	counter++;
     });
 
     $("#removeButton").click(function () {
	if(counter==1){
          alert("No More Rows to Remove");
          return false;
       }   
 
	counter--;
 
        $("#TextBoxDiv" + counter).remove();
 
     });
 
     $("#getButtonValue").click(function () {
 
	var msg = '';
	for(i=1; i<counter; i++){
   	  msg += "\n Textbox #" + i + " : " + $('#textbox' + i).val();
	}
    	  alert(msg);
     });
  });
</script>
		<script type="text/javascript">
$(document).ready(function(){
    $('#itm-qty').keyup(calculate);
    $('#itm-amnt').keyup(calculate);
});
function calculate(e)
{
    $('#total').val($('#itm-qty').val() * $('#itm-amnt').val());
}
    </script>

The first row for calculation works spot on.

But adding rows there after does not work at all.

 

And i lack an overall totals at the end as well.

 

Any help much appreciated!

You're creating multiple instances of the same ID (#item-qty and #itm-amnt). You should use the counter increment variable for each new input you're adding, like this:

 

<td><input class="itmqty" id="itm-amn'+ counter + '" placeholder="Insert Item ' + counter + '" type="text" name="data[' + counter + '][4]" id="invitem' + counter + '" ></td>

 

You're also appending every new <td> element with the same ID (id="invitem' + counter + '") which you shouldn't really be doing as ID's should be unique. E.g.

 


<td><input id="inv_itemcode' + counter + '"  /></td>
<td><input id="inv_itemname' + counter + '"  /></td>
<td><input id="inv_itemprice' + counter + '"  /></td>
<td><input id="inv_itemqty' + counter + '"  /></td>
<td><input id="inv_itemtotal' + counter + '"  /></td>

 

 

To resolve your calculation issue, you could use the class to get the ID of the dynamic row item clicked and then calculate based on that. I'll try and put a fiddle together for you.

Lyndsey is 100% correct with the above - but the whole problem could be simplified and solved using either class names or, better yet, HTML5 data-* attributes. To take Lyndsey's corrected example above an expand on it:

<tr>
<td><input data-field="itemcode" /></td>
<td><input data-field="itemname" /></td>
<td><input data-field="itemprice" /></td>
<td><input data-field="itemqty" /></td>
<td><input data-field="itemtotal" /></td>
</tr>
You can then use IDs for each row if you really want to, but I'd suggest using jQuerys .eq(), or just cycling through each row.

 

Quick example or cycling through (untested):

var getCalculatedTotal = function(){
    var total = 0;
    $(".product-table tr").each(function(){
        var qty = parseInt($(this).find("*[data-field='itemqty']").val());
        var price = parseFloat($(this).find("*[data-field='itemprice']").val());
        if (!isNaN(qty) && !isNaN(price)){
            total += qty * price;
        }
    });
    return total;
};

Edited by andy9l
Wording

I've put together this for you, it can probably be validated a little bit! But I hope it helps :)

 

http://jsfiddle.net/LyndseyB/TTjVK/1/

 

Note: I used the .on() method which is valid for jQuery 1.7 and above. If you're using anything lower, use .live().

 

Quick explanation:

  • Created each dynamic element with a class along with an ID e.g. <input class= "itmqty" id="#itemqty1" />.
  • Used the class to grab the ID of the input element clicked, and extracted the counter variable e.g. 1
  • Used the counter variable ($rowNum) to calculate the corresponding Total field e.g. $('#total'+rowNum).val(calc);

 

Update: added running total: http://jsfiddle.net/LyndseyB/TTjVK/2/

 

Sorry Andy, I didn't realise you'd posted!

 

Hope this helps,

Lyndsey.

An alternative, forked from Lyndsey's approach - just for the benefit of anyone who cares really :)

 

http://jsfiddle.net/andy9l/re2af/1/

 

Forgot the 10 limit:

 

http://jsfiddle.net/andy9l/re2af/3/

 

/Procrastination.

Edited by andy9l

Nice one Andy ^

 

First time I've seen the data-field attribute. I've come across something similar (data-role, data-icon etc) using jQuery Mobile but didn't think it existed in HTML. Will have to look that one up :D

 

Saying that, what am I on about? The data-role attribute was always loaded as part of the HTML. I'm being thick Andy, ignore me! lol :p

 

Thanks for the link!

Any element attribute with the data- prefix is "valid". You could have data-andy, data-lyndsey, data-wdf, etc. within most HTML elements (<input>, <a>, etc.).

 

More information is in the latest HTML5 spec draft from W3C: http://goo.gl/kQkxk

 

Edit: For some reason the link was going to some random part of the page - fixed with Goo.gl URL.

Edited by andy9l
Fixed link

  • Author

Awesome! Thanks guys! So how would i go about looping through those results to get a final total of all the Total fields?

Iv not tested yet but if the JS fiddle works, im happy.

 

Thanks again!

Awesome! Thanks guys! So how would i go about looping through those results to get a final total of all the Total fields?

Iv not tested yet but if the JS fiddle works, im happy.

 

Thanks again!

 

Updated the fiddle in my previous post to display running total:

 

Update: added running total: http://jsfiddle.net/LyndseyB/TTjVK/2/

 

You're welcome :)

  • Author

Thank you so very much! I am useless at JS but learnt something here i think. Im just looking through to see how its all happening.

  • Author

i have a header in there for the table as well.

 

<tr><td>Item code</td></tr>...

 

etc.

 

The code in there has find tr:first

 

I changed it to tr:second but it does not work. Any idea how i can get around that?

i have a header in there for the table as well.

 

<tr><td>Item code</td></tr>...

 

etc.

 

The code in there has find tr:first

 

I changed it to tr:second but it does not work. Any idea how i can get around that?

 

Just add a class to the row e.g.

 <tr class="cloneRow">
       <td><input placeholder="Item Code" name="data[0][0]" class="itmcode" /></td>
       .....

 

Then in your jQuery change all references of $('tr:first') to $('tr.cloneRow'). E.g:

 

var row = table.find("tr.cloneRow");
var thisRow = $(this).parents("tr.cloneRow");
  • Author

That fixed it Lyndsey, i should i have thought about that.

One thing i have noticed is (Sorry i should have mentioned this before), the name (data[0][1]), needs to be counting upward as a new row is added. ie:

 

row 1 should be:

 

data[0]

 

row 2:

 

data[1]

 

Also getting £NaN in the totals. I really do appreciate the helping hand as this has been a real headache trying to figure it out.

You could simply create the input name as an array, for example:

 

<input name="itemcode[]" id="itemcode1" class="itmcode" />
<input name="itemcode[]" id="itemcode2" class="itmcode" />

 

 

And then use PHP (or whatever server side language you're using) to loop through the submitted array:


foreach( $_POST['itemcode'] as $v ) {
    print $v;
}
  • Author

Here's a version with all the problems mentioned above fixed (header row, data[X] increment): http://jsfiddle.net/andy9l/re2af/7/

 

Edit: Fixed NaN issue.

Sorry to nitpick, but the NaN issue has turned into nothing at all. #total is always £0.00 no matter what. How come it works in jsfiddle yet iv copied it exact and its not working?

  • Author


<script type="text/javascript">
$(document).ready(function(){

var table = $("#TextBoxesGroup");
var row = table.find("tr").eq(1);
var count = 0;

$("#addButton").click(function(e){
if (table.find("tr").length >= 10){
alert("Maximum of 10 rows");
return;
}
var newRow = row.clone();
var regex = new RegExp("data\[[0-9]+\]", "g");
newRow.html(newRow.html().replace(regex, "data[" + (++count) + "]"));
table.append(newRow);
});

$(document).on('keyup', "*[data-field='quantity'],*[data-field='price']", function(e){
var thisRow = $(this).parents("tr:first");
var rowTotalField = thisRow.find("*[data-field='total']");
var price = parseFloat(thisRow.find("*[data-field='price']").val());
var quantity = parseInt(thisRow.find("*[data-field='quantity']").val());
rowTotalField.val("\u00A3" + (!isNaN(price) && !isNaN(quantity) ?
price*quantity : 0).toFixed(2));
var total = 0;
table.find("*[data-field='total']").each(function(){
var t = parseFloat($(this).val().replace("£", ""));
total += !isNaN(t) ? t : 0;
});
$("#total").text(total.toFixed(2));
});

});


$().ready(function() {
$(".autof").autocomplete("suggest.php", {
width: 260,
matchContains: true,
selectFirst: false
});
});
</script>


<table class="intro"id="TextBoxesGroup">
<tr id="tabletop"><td>Item Code</td><td>Item Name</td><td>Item Description</td><td>Price (£)</td><td>Qty</td><td>Total</td></tr>
<tr>
<td><input placeholder="Item Code" name="data[0][0]" class="autof" /></td>
<td><input name="data[0][1]" class="auto" placeholder="Item Name" /></td>
<td><input name="data[0][2]" class="auto" placeholder="Item Description" /></td>
<td><input data-field="price" name="data[0][3]" placeholder="Item Amount" class="auto" /></td>
<td><input data-field="quantity" name="data[0][4]" placeholder="Item Quantity" class="itmqty" /></td>
<td><input data-field="total" name="data[0][5]" placeholder="Item Total" readonly="readonly" /></td>
</tr>
</table>
<h2>Total Cost: £<span id="total">0.00</span></h2>

<input type='button' value='Add Item' id='addButton'>
<input type='button' value='Remove Item' id='removeButton'><br/>
Send to Client: <input <?php echo $emailit; ?> type="checkbox"/><br/><br/>
<input type="submit" value="Send" />

If I copy and paste that code, it works. That would suggest your autocomplete plugin is causing troubles.

 

Check console errors, post them here.

  • 7 years later...

Hi,

Found this code still relevant today.

I need help with delete button on each row which i added, but it doesn't reset total if any rows are deleted after updating fields.

Any help on same largely appreciated.

Edited by pravinc

  • 3 months later...

Hello,

 

I've been looking at this and was hoping someone can help.  I want to add in the JS code VAT rate at a fixed rate and than have some fields at the bottom do sub total and Vat and Total.

 

Can you please show the how the code can be updated to include these fields also.

 

Thank You

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.