0

I am currently implementing a triple dependent drop-down menu (think country->state->city) that is populated with AJAX requests.

Here is the code snippet of my drop-down structure:

        //create a drop down of available accounts
        echo 'Available Accounts: ';

        echo '<select name="dropAccounts" class="dropAccounts">';
        //if there is at least one account available
        if (count($accsAvailable) > 0) {
            echo '<option value="0">---Select an account---</option>'; //default option
            foreach ($accsAvailable as $account) {
                //populate from API
                echo '<option value=' . $account->getId(). '>' . $account->getName() . '</option>';
            }
        } else {
        echo '<option value="0">---No accounts available---</option>'; //else if no accounts exist
    }
    echo '</select>';

    //for available webproperties
    echo '<br> Available Webproperties: ';
    echo '<select name="dropProperties" class="dropProperties">';
    echo '<option selected="selected">---Select a webproperty---</option>';
    echo '</select>';

    //for available profiles
    echo '<br> Available Profiles: ';
    echo '<select name="dropProfiles" class="dropProfiles">';
    echo '<option selected="selected">---Select a profile---</option>';
    echo '</select>';

The important variables are dropAccounts (country), dropProperties (state), and dropProfiles (city). The first drop-down is populated by an API call, and from there, an AJAX request grabs the value from it on an onchange event as such:

<script type="text/javascript">
    $(document).ready(function()
    {
        $(".dropAccounts").change(function()
        {
            var accountID = $(this).val(); //gets the account ID from drop-down value

            $.ajax
            ({
                type: "POST",
                url: "propertyID.php",
                data: {
                    'accountID' : accountID
                },
                cache: false,
                success: function(html)
                {
                    $(".dropProperties").html(html);
                } 
            });

        });

    });
</script>

then propertyID.php then populates dropProperties as such (assume I am grabbing the values from a database):

if($_POST['accountID'])
{  
    if ($accountID != "0") {
        foreach ($webItem as $item) {
            echo '<option value=' . $item->getId() . '>' . $item->getName() . '</option>';
        }
    }
}
else {
    echo '<option value="0">---Select a webproperty---</option>';
}

I have similarly set up the third drop-down menu (dropProfiles) to populate in the exact same way, assuming when the second drop-down menu repopulates that it triggers the javascript onchange event. However, when I get the second drop-down to repopulate, it doesn't execute the javascript for the third drop-down.

Here is the javascript onchange function that should trigger the PHP script to populate dropProfiles:

<script type="text/javascript">
    $(document).ready(function()
    {
        $(".dropProperties").change(function()
        {
            var id = $(this).val(); //gets the profile ID from drop-down value

            $.ajax
            ({
                type: "POST",
                url: "profileID.php",
                data: {
                    'id' : id
                },
                cache: false,
                success: function(html)
                {
                    $(".dropProfiles").html(html);
                } 
            });

        });

    });
</script>

Is there a workaround to this? Am I approaching this the wrong way?

eluong
  • 701
  • 1
  • 7
  • 17

2 Answers2

3

Your best bet is to manually call your "populate" functions when you want to load the cascaded values. To do this, you'll need to break them out into named functions. This gives you the ability to trigger dropdown population at any point.

$(document).ready(function()
{

    function populateProperties(accountId) {
        $.ajax
        ({
            type: "POST",
            url: "propertyID.php",
            data: {
                'accountID' : accountId
            },
            cache: false,
            success: function(html)
            {
                $(".dropProperties").html(html);

                // Populate profiles after properties load
                populateProfiles($(".dropProperties").val());
            } 
        });

    }

    function populateProfiles(propertyId) {
        $.ajax
        ({
            type: "POST",
            url: "profileID.php",
            data: {
                'id' : propertyId
            },
            cache: false,
            success: function(html)
            {
                $(".dropProfiles").html(html);
            } 
        });
    }

    $(".dropAccounts").change(function()
    {
        var accountID = $(this).val(); //gets the account ID from drop-down value
        populateProperties(accountID);
    });

    $(".dropProperties").change(function()
    {
        var id = $(this).val(); //gets the profile ID from drop-down value
        populateProfiles(id);
    });

    // Call populateProperties on page load to kick things off
    populateProperties($(".dropAccounts").val());
});
itsananderson
  • 783
  • 5
  • 9
  • @Will Still no luck, the function for populating the second drop-down is working fine, but the third PHP script is still not executing. – eluong May 09 '14 at 15:10
  • I probably have a typo or something. I'll test and see if I can figure out what's going wrong. – itsananderson May 09 '14 at 15:25
  • @WillAnderson Thanks for all the help! If it helps you with the debug, I don't think the `$(".dropProperties").change()` is executing at all because I think the code is replacing the entire drop-down. Could be wrong though. – eluong May 09 '14 at 15:39
  • I think I found it. `'accountID' : accountID` should have been `'accountID' : accountId`. With that change, the dropdowns seem to cascade properly. I updated my answer with the fix – itsananderson May 09 '14 at 16:22
  • @WillAnderson I was able to get the third script to execute after fixing the typo, but the `populateProfiles($(".dropProperties").val());` call in the `populateProperties` method is passing the value of `dropAccounts` for some reason. – eluong May 09 '14 at 17:55
  • It's also making an abnormally high amount of requests, as if it is infinitely looping. The performance is pretty slow, but I don't see how this is possible in the code. The two external scripts used, `profileID.php` and `propertyID.php` are being executed hundreds of times! – eluong May 09 '14 at 18:30
  • I wonder if there's a difference between what you've posted and what I'm using to test. I didn't test with the PHP backend, but that shouldn't make a big difference. Here's a punker of what I tried: http://plnkr.co/edit/byUAtOCuc8ecqnyUHOee?p=preview – itsananderson May 09 '14 at 18:32
  • @WillAnderson It turns out with my implementation that calling `populateProperties($(".dropAccounts").val());` to do the initial population would induce an infinite loop somehow. I rectified it by putting a dummy initial value in `dropAccounts` and from there you can populate the other drop-downs by selecting a valid option. The only problem with this now is that for some reason, `if($_POST['id'])` in **profileID.php** is not passing as true, therefore not populating the final drop-down. Checking the value, it looks to be passing the value of the first entry of `dropAccounts`. Any suggestions? – eluong May 09 '14 at 20:01
  • Try `print_r( $_POST )` from profileID.php to test what data your PHP script is getting? This discussion has gotten a little off topic from the original question. Shoot me an email (will at itsananderson.com) if you still need help debugging your backend. – itsananderson May 09 '14 at 21:25
  • After debugging my backend, this works just fine. Thank you! :) – eluong May 12 '14 at 13:55
1

Events aren't triggered by value changes in the code

The onchange event must be triggered by user action or explicitly triggered by the script.

You may benefit from using jQuery's .trigger() method.

A similar question and answer can be found here: Trigger "onchange" event

Community
  • 1
  • 1
gfullam
  • 11,531
  • 5
  • 50
  • 64
  • Thanks for the suggestion! I am very new to JS and AJAX, is it still possible to make the AJAX request using the .trigger() method? – eluong May 09 '14 at 14:53
  • You wouldn't use .trigger() to make an AJAX request, but if your AJAX request is inside of a function triggered by an onchange request, you can manually trigger the onchange event using the .trigger() method. – gfullam May 09 '14 at 14:58
  • Also, if your third drop-down list is dependent on the second drop-down list, then the mere act of a user making a selection should trigger the function that makes the AJAX request to get your third menu's content. So, programmatically triggering the onchange event shouldn't even be necessary in this case. – gfullam May 09 '14 at 15:00
  • For your use case, I think the answer by @WillAnderson is the right solution. – gfullam May 09 '14 at 15:04