24

I'm adding select elements dynamically, like in the below HTML. I'm not sure why the .on('change' ...) is not working for the dynamic select. What am I missing?

I'm using Chrome 24.0.1312.57 + jquery 1.8.3.

<script type="text/javascript">
  $(document).ready(function() {
      $('#x select').on('change', function () { alert('helo'); })
      $('#y select').on('change', function () { alert('helo'); })

      $('#x').html($('#y').html());
  });
</script>

<div id="x"></div>
<div id="y">
    <select>
        <option>O1</option>
        <option>O2</option>
    </select>
</div>
jaime
  • 2,234
  • 1
  • 19
  • 22
  • set onchange attribute of dynamic element and create a function for it, this approach is easier – smrf Jan 24 '21 at 13:58

10 Answers10

39

Your code:

$('#x select').on('change', function () { alert('helo'); })

attaches an event handler to the select inside the #x element.

What you want (from what i understood) is something in the lines of:

$("#y").on('change','select',function () { alert('helo'); });

This attaches an event handler to the #y element that gets delegated to its children 'select' elements

From http://api.jquery.com/on/

The .on() method attaches event handlers to the currently selected set of elements in the jQuery object.

cernunnos
  • 2,766
  • 1
  • 18
  • 18
  • It is strange though, since the `#y` never actually changes. Only it's html content is copied over to the other element. Why should it fire change in this case? – Zelphir Kaltstahl Mar 22 '17 at 11:30
14

Event binding to elements that are not in the DOM on initial page load will not work. You need to bind to an element further up the DOM that exists to allow the event to trickle down. This is usually the approach that I take:

$(document).on({
  change: function() {
    alert('helo');
  }
}, '#x select');

$(document).on({
  change: function() {
    alert('helo');
  }
}, '#y select');

I prefer it as you can add subsequent events easily.

$(document).on({
  change: function() {
    alert('helo');
  },
  blur: function() {
    alert('helo');
  }
}, '#x select');
d_ethier
  • 3,873
  • 24
  • 31
  • 6
    Or the more recent syntax `$(document).on('change', '#x select', function() { alert('hello'); });` – duanev Jul 31 '14 at 00:08
6

Don't use .live()/.bind()/.delegate(), though. You should use .on().

for both static and dynamic select changes

$(document).on('change', 'select', function (e) {
    // do something 
});
user889030
  • 4,353
  • 3
  • 48
  • 51
3

Your event binding is set on $(document).ready(). However, if you are dynamically adding them later (like via jQuery.appendTo() or the like), the newly added components need to be binded since they were not part of the inital one that happened in $(document).ready(), which only runs once when the page is loaded and the DOM is initially done.

CodeChimp
  • 8,016
  • 5
  • 41
  • 79
1

Correct syntax:

 $('#x').on(
        'change', 
         'select', 
          function () { 
            alert('helo'); 
          }
       );

So syntax of on() for dynamic element seems:

$(staticParent).on( eventName, target, handler);
thecodeparadox
  • 86,271
  • 21
  • 138
  • 164
1

The whole point of .on() is so that you can bind the event to something other than the document. This is what the now depreciated .live() did and it is inefficient in most cases. You are ment to bind the event to the closest parent element that will not be dynamically changed.

As far as I am aware this is the correct syntax:

$('#x').on('change', 'select', function(){
    alert('hello');
});

If #x or #y will be changed, wrap them on an element and bind the event to that.

jamesbat.es
  • 53
  • 2
  • 9
1

This is easy. Whatever class or id your targeting, try being more precise but no need to include a super parent.

Example of wrong way:

        $('#tablecontent').on('change', '#tablecontent > table.CampaignGrid > tbody > tr > td', function(e) {
            console.log('IN TABLE CONTENT CHANGE');
            var value = e.target.value;
            $('button#updateLuck').prop('disabled', false).css({'color': '#000', 'font-weight': 600});

            //alert($(ele[0]).html());
        });

CORRECT WAY:

        $('#tablecontent').on('change', 'table.CampaignGrid > tbody > tr > td', function(e) {
            console.log('IN TABLE CONTENT CHANGE');
            var value = e.target.value;
            $('button#updateLuck').prop('disabled', false).css({'color': '#000', 'font-weight': 600});

            //alert($(ele[0]).html());
        });

Notice I dropped the super parent: '#tablecontent'

It all about clarity.

  • V
VickenCode
  • 305
  • 2
  • 12
1

        $('#tablecontent').on('change', '#tablecontent > table.CampaignGrid > tbody > tr > td', function(e) {
            console.log('IN TABLE CONTENT CHANGE');
            var value = e.target.value;
            $('button#updateLuck').prop('disabled', false).css({'color': '#000', 'font-weight': 600});

            //alert($(ele[0]).html());
        });

        $('#tablecontent').on('change', '#tablecontent > table.CampaignGrid > tbody > tr > td', function(e) {
            console.log('IN TABLE CONTENT CHANGE');
            var value = e.target.value;
            $('button#updateLuck').prop('disabled', false).css({'color': '#000', 'font-weight': 600});

            //alert($(ele[0]).html());
        });

        $('#tablecontent').on('change', 'table.CampaignGrid > tbody > tr > td', function(e) {
            console.log('IN TABLE CONTENT CHANGE');
            var value = e.target.value;
            $('button#updateLuck').prop('disabled', false).css({'color': '#000', 'font-weight': 600});

            //alert($(ele[0]).html());
        });

        $('#tablecontent').on('change', '#tablecontent > table.CampaignGrid > tbody > tr > td', function(e) {
            console.log('IN TABLE CONTENT CHANGE');
            var value = e.target.value;
            $('button#updateLuck').prop('disabled', false).css({'color': '#000', 'font-weight': 600});

            //alert($(ele[0]).html());
        });
Dominic
  • 31
  • 4
1

The word in square brackets is the alt text, which gets displayed if the browser can't show the image. Be sure to include meaningful alt text for screen-reading software.

Dominic
  • 31
  • 4
0

Came across this as I could not get my dynamically created selects which came back from an ajax post with dynamic id's, to trigger the event.

$(document).on('change', 'select', function (e) {
    $("#theDiv select").on("change",function(){ post("SelectChanged");} );
});

This would not work until I had changed something first so I added

$("#theDiv select").on("change",function(){ post("SelectChanged");} );

However this not meant, that after the change, all other changes then fired twice. This may not be very good practice. But what I did was to to put in a function that is called at the start and each return of ajax.

 `function myFuncs(){
    $('#theDiv select').unbind('change');
    $('#theDiv select').on('change' function(){ post('selectChanged'); });
  }`

But had to unbind at start of each function call else it doubled up the functions each time. I am sure there must be a proper way to do this, I just haven't found it yet. Thanks for starting the question.

Naxia
  • 9
  • 4