1

I have four <select> element.

<div id="select-countries-container">
        <select name="countryId" id="select-countries">
            <option value="">Choose Country &raquo;</option>
        <?php foreach($location->fetch(array('table' => 'countries')) as $country) { ?>
            <option value="<?php echo $country['id']; ?>"><?php echo $country['name']; ?></option>
        <?php } ?>
    </select>
</div>
<div id="select-states-container"><select disabled="disabled"><option value="">Choose State &raquo;</option></select></div>
<div id="select-cities-container"><select disabled="disabled"><option value="">Choose City &raquo;</option></select></div>
<div id="select-areas-container"><select disabled="disabled"><option value="">Choose Area &raquo;</option></select></div>

the child element <select> is replaced with the code received from Ajax, here is the Ajax Code i am using.

$('#select-countries').change(function(){
    var countryId = $(this).val();
    if(countryId == ''){
        $('#select-states-container').html(chooseState);
    } else {
        $.ajax({
            type: 'POST',
            url:  'process.php',
            data: 'countryId='+countryId,
            beforeSend: function() {
                $('#select-states-container').html(loadingText);
            },
            success: function(states){
                if(states == 'null') {
                    $('#select-states-container').html(emptyState);
                } else {
                    $('#select-states-container').html(states);
                }   
            }
        });
    }
});

and the data being retrieved from process.php is.

$select  = '<select name="stateId" id="select-states">';
$select .= '<option value = "">Choose State &raquo;</option>';
foreach($states as $state) {
    $select .= '<option value = "'.$state['id'].'">'.$state['name'].'</option>';
}
$select .= '</select>';
echo $select;

till here it works perfectly fine, the trouble starts when i select states from second <select> i.e <select name="stateId" id="select-states"> retrieved from process.php, when i select the value from this it does not trigger the function it is bound to, i am not sure what is happening, here is what i tried to do.

$('#select-states').change(function(){
        alert('Fire');
});

and this does not fire. what is wrong with my code?

thanks.

Ibrahim Azhar Armar
  • 25,288
  • 35
  • 131
  • 207

2 Answers2

2

You should use .live().

From the documentation:

Description: Attach a handler to the event for all elements which match the current selector, now and in the future.

barfoon
  • 27,481
  • 26
  • 92
  • 138
1

You need to use delegate() to add the change handler to dynamically-created elements:

$("body").delegate("#select-states", "change", function(){
    ...

This is necessary because your existing code runs only once ( when the document is loaded, presumably) and binds the event handler only to the elements that exist at that time. Delegate will bind the event all existing elements, plus all elements that are created in the future. For more information, please see the jQuery delegate documentation.

If you wish, you can use bind() instead. You would place the call to bind() in the AJAX call's success function to attach the event handler to the element after it is created.

EDIT

For a good analysis on the differences between delegate() and live(), see jQuery: live() vs delegate()

Community
  • 1
  • 1
George Cummins
  • 28,485
  • 8
  • 71
  • 90
  • 2
    If you're going to set it on `body`, why not just use `live`? – James Montagne Jul 28 '11 at 18:40
  • not sure but it is not working i tried using this code `$("body").delegate('#selected-states', 'change', function(){ alert('fire');});` :( – Ibrahim Azhar Armar Jul 28 '11 at 18:42
  • @Ibrahim Azhar Armar: '#selected-states' is not a valid identifier. Should it be '#select-states'? – George Cummins Jul 28 '11 at 18:46
  • @kingjiv: `live()` works fine in many cases, as long as you heed the many caveats listed in the documentation. `delegate()` is more flexible and applies to a wider variety of situations and events. – George Cummins Jul 28 '11 at 18:47
  • I guess I'll have to read up on it again. I thought all of the same caveats applied to delegate except it was more targeted. – James Montagne Jul 28 '11 at 18:49
  • @George, how could be `#selected-states` not a valid identifier? i copy pasted the code from my script. i am really not sure on why isn't `.delegate()` working for me :(, is it okay for me to go with `.live()` ? – Ibrahim Azhar Armar Jul 28 '11 at 19:01
  • @Ibrahim Azhar Armar: In your post, you said you defined your element as: ` – George Cummins Jul 28 '11 at 19:03
  • so do you suggest i rename the selector and use `.delegate()`, i am a novice in JS, can `.live()` be problematic for me? – Ibrahim Azhar Armar Jul 28 '11 at 19:07
  • @Ibrahim Azhar Armar: If `live()` works for you, you can use it (either way, your selector needs to match the element). Just keep in mind the [caveats in the documentation](http://api.jquery.com/live/#caveats), and consider examining the link I added to my answer. `delegate()` is more efficient, and works in situations where `live()` may not. – George Cummins Jul 28 '11 at 19:11