1

I have some JS that dynamically creates a new div (inputs inside of a form). It works great. I separately have some jquery that checks a dropdown input, and shows a separate div if a specific selection is clicked. It works great.

If I try to use the jquery to show a separate div inside one of the dynamically created ones, it does not work. The first instance of it does work, but none of the dynamically created ones. After searching around, it looks like I need a delegation, but I can't seem to figure it out for my specific situation.

The JSFiddle: http://jsfiddle.net/Xyzeg/ (change the "CPI" dropdown in the first field, for the event to go off). The fiddle includes the other JS for dynamically creating the divs.

Any pointers would be appreciated.

<div style="float:left">
<div id='dynamicInput'>Pension 1: Amount: $<input type='text' name='adjustmentInputs[]' value='0' size='13' maxlength='20'>Start Year:
<input type='text' name='adjustmentInputs[]' value='2032' size='5' maxlength='6'>
<input type='hidden' name='adjustmentInputs[]' value='2100'>
<select name='adjustmentInputs[]'>
  <option value='InflationAdjusted'>Inflation Adjusted</option>
  <option value='NotInflationAdjusted'>Not Inflation Adjusted</option>
</select>by
<select name='adjustmentInputs[]' class='pensionAdjustment1'>
  <option value='CPI'>CPI</option>
  <option value='constantPercentage'>Constant %</option>
</select>
<div id='constantPercentageText1' style='display: none'>@ <input type='text' name='adjustmentInputs[]' value='3' size='5' maxlength='6'>%</div>
</div>
   <input type="button" value="Add another Portfolio Adjustment" onClick="addInput('dynamicInput');">
</div>
<script>
$("[class*=pensionAdjustment]").change(function() {
    var n = $(this).attr('class').replace('pensionAdjustment', '');
    var newId = "constantPercentageText" + n;
    var selectedItem = $(this).children('option:selected');
    if ($(this).val() == 'constantPercentage') {
        $("#constantPercentageText" + n).css('display', 'inline');
        $("#constantPercentageText" + n).show();
    } else {
        $("#constantPercentageText" + n).css('display', 'none');
    }
});  
</script>
bo_knows
  • 856
  • 2
  • 9
  • 20
  • You must delegate events to an element which exists at the time the events are bound. – Evan Davis Jul 16 '13 at 18:21
  • To expand on @Mathletics comment, check out jQuery.on. `$(document).on('change', "[class*=pensionAdjustment]", function() {...` – dinjas Jul 16 '13 at 18:22
  • So, you're saying that because the dynamically created divs don't exist before the search occurs, I can't bind the events like I am? What's the solution then? – bo_knows Jul 16 '13 at 18:23

3 Answers3

3

You need to delegate with newly created elements!

Change this line

$("[class*=pensionAdjustment]").change(function() {

to

$(document).on('change',"[class*=pensionAdjustment]",  function() {
Zevi Sternlicht
  • 5,399
  • 19
  • 31
  • I can't quite accept the answer yet (too early, too new a user), but this did the trick. Can you explain what's going on here a bit? So I can actually learn the difference. – bo_knows Jul 16 '13 at 18:25
  • @bo_knows cool, no problem, its one of those things to get used to in jQuery, will solve a lot of newbie errors! – Zevi Sternlicht Jul 16 '13 at 18:25
  • the $(document).on part is assigning a delegation for future created content? – bo_knows Jul 16 '13 at 18:26
  • Instead of choosing elements that were there at load time, we are looking for actual live elements! – Zevi Sternlicht Jul 16 '13 at 18:26
  • ahhh. So anything that isn't on load (something got changed) needs to use on()? I appreciate the explanation – bo_knows Jul 16 '13 at 18:27
  • 2
    Yes. The reason this helps is because the `document` object was around at load time. `Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.` – Zevi Sternlicht Jul 16 '13 at 18:28
  • Excellent. Now I just need to get rid of my "old" JS that does the dynamically adding of the divs, and I'll be nice an sleek with all jquery. Good times. But, that's not on my radar at the moment. Cheers! – bo_knows Jul 16 '13 at 18:29
  • @bo_knows why get rid of it, just make sure to use delegates, `on()` instead of direct of eventHandlers – Zevi Sternlicht Jul 16 '13 at 18:30
3

You can use

$(document).on('change', '[class*=pensionAdjustment]', function(){
    // your code
});

It would be better if you use a parent div, instead of document.

Update : The elements you are injection dynamically to the DOM were not present when the event was registered, so new elements are not firing the event. Using event delegation, (registering the event on a parent element) this could be solved because when any element fires an event, the event bubbles up to the last element (upwards) it can find and this way the parent element is being triggered but behind the scene, something like following is happening

e = e || window.event;
var el = e.target || e.srcElement;

You may check this.

The Alpha
  • 143,660
  • 29
  • 287
  • 307
0

You have to bind the event to a parent element, then filter down to the one you want. This way it doesn't matter when the element is added, it will always work. This is called delegation. You delegate the task of handling the event to another element.

$(document).on('change', "[class*=pensionAdjustment]", function(){
    var n = $(this).attr('class').replace('pensionAdjustment', '');
    var newId = "constantPercentageText" + n;
    var selectedItem = $(this).children('option:selected');
    if ($(this).val() == 'constantPercentage') {
        $("#constantPercentageText" + n).css('display', 'inline');
        $("#constantPercentageText" + n).show();
    } else {
        $("#constantPercentageText" + n).css('display', 'none');
    }
});
Jonny Sooter
  • 2,417
  • 1
  • 24
  • 40