1

In my invoicing web application I am trying to calculate the item totals of an invoice on the client side with jQuery:

$(function() {

  // Add a new row of item fields
  $('form.edit_invoice').on('click', '.add_fields', function(event) {   
    var regexp, time;
    time = new Date().getTime();
    regexp = new RegExp($(this).data('id'), 'g');
    $(this).closest('tr').before($(this).data('fields').replace(regexp, time)); // Replace ID with a unique ID
    calculateItemTotals();      
    event.preventDefault();
  });   

  // Update item total when item price or quantity gets changed
  $('input[id$="_price"], input[id$="_quantity"]').on('change', function() {
    calculateItemTotals();  
  });

});

function calculateItemTotals() {
  $('.item_fields').each(function() {

    var price = $(this).find('input[id$="_price"]').val();
    var quantity = $(this).find('input[id$="_quantity"]').val();

    var total = parseFloat(price) * parseFloat(quantity);

    $(this).find('.item_total').text(total);    
  });   
}

This works for invoices where all items have already been saved.

When creating a new invoice, however, items are added dynamically through jQuery and the above function doesn't work.

How can I get it to work with those items as well?

Thanks for any help.

Update:

This is the link that creates a new invoice item:

<a class='add_fields icon_link new' data-fields='<tr class="item_fields">   <td width="13%" data-title="Date">      <input class="item-datepicker" id="" type="text" value="20.10.2014" /><input id="invoice_items_attributes_2236275320_date" name="invoice[items_attributes][2236275320][date]" type="hidden" value="2014-10-20" />   </td>   <td width="42%" data-title="Description">   <input id="invoice_items_attributes_2236275320_description" name="invoice[items_attributes][2236275320][description]" type="text" value="Erstellung einer Website" />   </td>   <td width="15%" data-title="Price">     <input id="invoice_items_attributes_2236275320_price" min="0" name="invoice[items_attributes][2236275320][price]" type="number" value="50.0" /> </td>       <td width="10%" data-title="Qty">   <input id="invoice_items_attributes_2236275320_quantity" min="0" name="invoice[items_attributes][2236275320][quantity]" type="number" value="1" />  </td>   <td width="10%" data-title="Total">     <span class="item_total">0</span>   </td>       <td width="10%">        <input id="invoice_items_attributes_2236275320__destroy" name="invoice[items_attributes][2236275320][_destroy]" type="hidden" value="false" />      <a class="remove_fields icon_link destroy" href="#">Remove</a>  </td></tr>' data-id='2236275320' href='#'>Add item</a>
Tintin81
  • 9,821
  • 20
  • 85
  • 178
  • 1
    How is that function called? You're re-running the selector so it should include dynamic elements. – Anthony Grist Oct 20 '14 at 11:39
  • 1
    In which scenario you are calling the `calculateItemTotals` method – Usha Oct 20 '14 at 11:43
  • 2
    If you call calculateItemTotals function after dynamic content load,then it will work. make sure you call your function after content loading is complete. this can be more clear if you provide jsfiddle demo. – bharatpatel Oct 20 '14 at 11:48
  • Check this question http://stackoverflow.com/questions/19325938/trigger-action-on-programmatic-change-to-an-input-value , might be of use – Master Slave Oct 20 '14 at 11:57

1 Answers1

2

It turns out to be standard (asked many times) problem with dynamically created elements: for dynamically created elements you should use delegated event handlers with .on():

$('form.edit_invoice').on('change', 'input[id$="_price"], input[id$="_quantity"]', function()
{
    calculateItemTotals();  
});

Fiddle example.

Regent
  • 5,142
  • 3
  • 21
  • 35
  • Excellent, thank you so much! Even I vaguely remember having read about this. You are completely right, my code works now! – Tintin81 Oct 20 '14 at 12:37