0

I've followed the Railscast on creating a Nested Model Form and am successfully adding and removing fieldsets via Javascript as it demonstrates.

In my project I need to some on change functions to apply to the newly created fields; I have a price field and on changing this need to display a net return value to the user for example.

If I create the fields, save and then edit, my on change functions work fine but they do not work on any new fields/fieldsets added before the parent object is saved.

In short, how do I make my JS functions apply to fields created via JS?

The JS function I'm trying to apply to these newly created fields is as follows and this is contained in a document ready:

$('.ticket-price').each(function() { $(this).change(function() { var ticket_price = $(this).val(); if (ticket_price == 0) { fee_rate = 0 } else if (ticket_price >= 0.01) { fee_rate = 0.10 } var booking_fee = ticket_price * fee_rate var customer_pays = parseFloat(ticket_price) + parseFloat(booking_fee) var vendor_fee = ((customer_pays / 100) * 3.5) +0.2 var vendor_receives = (parseFloat(ticket_price) - vendor_fee ) $(this).parent().next().children('input.booking-fee').val(booking_fee.toFixed(2)).effect( "highlight", {color:"#FFFF33"}, 1500 ); $(this).parent().next().next().children('input.vendor-receives').val(vendor_receives.toFixed(2)).effect( "highlight", {color:"#FFFF33"}, 1500 ); }); }); 

Would I be correct in thinking as this is in document ready, the new fields are therefore not seen by this? How do I go about getting them 'seen'?

EDIT: New version of code, where I get strange behaviour. Only the second on change event is seen and then the highlight occurs based on the number of times the change is made.....so if three changes were made to the ticket price field it 'pulses' yellow three times.

$(document).on('change', '.ticket-price', function() { $(this).change(function() { var ticket_price = $(this).val(); if (ticket_price == 0) { fee_rate = 0 } else if (ticket_price >= 0.01 && ticket_price <= 25.00) { fee_rate = 0.10 } else if (ticket_price >= 25.01 && ticket_price <= 40.00) { fee_rate = 0.08 } else if (ticket_price >= 40.01 && ticket_price <= 60.00) { fee_rate = 0.07 } else if (ticket_price >= 60.01) { fee_rate = 0.06 } var booking_fee = ticket_price * fee_rate var customer_pays = parseFloat(ticket_price) + parseFloat(booking_fee) console.log(customer_pays); var vendor_fee = ((customer_pays / 100) * 3.5) +0.2 var vendor_receives = (parseFloat(ticket_price) - vendor_fee ) console.log(booking_fee); console.log(vendor_receives); $(this).parent().next().children('input.booking-fee').val(booking_fee.toFixed(2)).effect( "highlight", {color:"#FFFF33"}, 1500 ); $(this).parent().next().next().children('input.vendor-receives').val(vendor_receives.toFixed(2)).effect( "highlight", {color:"#FFFF33"}, 1500 ); }); }); 

    2 Answers 2

    1

    Do this:

    $(document).on('change', '.ticket-price', function() { var ticket_price = $(this).val(); ... }); 

    This way instead of binding your event to the HTMLElements currently on page, you are telling jQuery to watch the entire document for changes on any elements with the 'ticket-price' class. Even ones that are added dynamically.

    Here's a sample jsFiddle: http://jsfiddle.net/64eLt/2/

    6
    • I've just given this a go and it's very close but seems to only pick up the second on change event. Any ideas?
      – Raoot
      CommentedDec 3, 2013 at 19:02
    • You mean you have to change twice for it to happen? Could you update your original question with the new code so I can take a look?CommentedDec 3, 2013 at 22:03
    • I've added the new code as requested. This now sits outside of the document ready where it used to live. Other than the issue with having to change it more than once for it to work, there's also an issue with it then running the code for the number of on change events.....so I get a strange pulsing effect on the highlight.
      – Raoot
      CommentedDec 4, 2013 at 11:28
    • I see the problem. You have to remove the second ($(this).change(function() { and second to last }); lines of code. What you are doing is this: You are telling javascript that when the document notices that an element with ticket-price class is changed, it should bind a change event to it. So every time it changes, a new event is bound. That's why it only works after the first change and its pulsing.CommentedDec 4, 2013 at 11:50
    • Cool, that's spot on now. Not sure I full understand how it's identifying which instance of .ticket-price has changed as my original had the lines $('.ticket-price').each(function() { $(this).change(function() { where the each and then this references made sense to me. Thanks for your help!
      – Raoot
      CommentedDec 4, 2013 at 11:57
    0

    Okay, I think the problem you have is that your Javascript is not picking up the dynamically-added items


    Dynamic DOM

    Javascript (and JQuery by virtue of inheritance) works by binding elements in the DOM (Document Object Model) to events. These events are described by you with your functions, and Javascript basically adds "listeners" to the various elements you include

    The problem you have is when you're updating the DOM, your new elements are not bound to any functions you assigned when the document loaded, thus preventing them from working

    The solution to this, as pointed out by the other answer, is to delegate your function from the document to the elements you wish to change, like this:

     $(document).on("change", ".ticket_price",function() { //do stuff here }); 

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.