5

I have an aspx Master page application where I have two dropdownlist controls in the asp:content section of the child aspx page. One of the controls is populated from SQL database. The other is populated based on the item selected from the first dropdown. I am trying to use this solution in my code, however I am getting an error:

JavaScript runtime error: Unable to get property 'forEach' of undefined or null reference

How can I get the city names to be displayed based on State selected?
My code block is:

  <link rel="stylesheet" href="//code.jquery.com/ui/1.11.1/themes/smoothness/jquery-ui.css">
  <script src="//code.jquery.com/jquery-1.10.2.js"></script>
  <script src="//code.jquery.com/ui/1.11.1/jquery-ui.js"></script>

    <script type="text/javascript">
        AL = new Array('Birmingham', 'Montgomery', 'Tuscaloosa');
        FL = new Array('Miami', 'FtLauderdale', 'Jacksonville');
        GA = new Array('Atlanta', 'Macon', 'Athens');

        populateSelect();

        $(function () {

            $('#ddlState').change(function () {
                populateSelect();
            });

        });

        function populateSelect() {
            category = $('#ddlState').val();
            $('#ddlCity').html('');

            eval(category).forEach(function (t) {
                $('#ddlCity').append('<option>' + t + '</option>');
            });
        }
    </script>  

<asp:DropDownList ID="ddlCity" runat="server" CssClass="stdFldWidth" onchange="setFDFlag()">
</asp:DropDownList>    

<asp:DropDownList ID="ddlState" runat="server" CssClass="stdFldWidth" DataSourceID="dsUSState"
    DataTextField="US_State" DataValueField="State_ID" AutoPostBack="true" > 
</asp:DropDownList>  

Update:

Protected Sub ddlState_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles ddlType.SelectedIndexChanged
If ddlState.SelectedValue = "FL" Then
    DisplayRegulation(FL)
End If
Community
  • 1
  • 1
user3929962
  • 517
  • 3
  • 6
  • 23

2 Answers2

3

The common issue with ASP.NET pages, specially if you use MasterPages.

The generated pages will have their elements IDs changed.

One solution for your problem is to give these elements a unique class and use it in the selector instead of their IDs:

<asp:DropDownList ID="ddlCity" runat="server" CssClass="stdFldWidth ddlCity" onchange="setFDFlag()">
</asp:DropDownList>    

<asp:DropDownList ID="ddlState" runat="server" CssClass="stdFldWidth ddlState" DataSourceID="dsUSState"
    DataTextField="US_State" DataValueField="State_ID" AutoPostBack="true" > 
</asp:DropDownList>

...

$(function () {
    var states = {
        AL: ['Birmingham', 'Montgomery', 'Tuscaloosa'],
        FL: ['Miami', 'FtLauderdale', 'Jacksonville'],
        GA: ['Atlanta', 'Macon', 'Athens']
    };

    function populateSelect() {
        $('.ddlCity').empty();

        var stateSelected = $('.ddlState').val();

        if (stateSelected) {
            states[stateSelected].forEach(function (sel) {
                $('<option>').val(sel).text(sel).appendTo($('.ddlCity'));
            });
        }
    }

    populateSelect();

    $('.ddlState').on('change', function() { 
        populateSelect();

        return true;
    });
});

Edited using @sebnukem recommendation to keep the data in an object, so you can get rid of the eval().

Updated by placing the whole code within the jQuery document ready event handler.

Updated by returning true in the jQuery onchange event handler for the DropDownList, to carry on with the PostBack.

Demo

emerson.marini
  • 9,331
  • 2
  • 29
  • 46
  • I updated my original post with the codebehind. I tried adding the values to ddlCity in the codebehind, but it didnt work. I was thinking jquery would be an easier option. – user3929962 Sep 09 '14 at 18:49
  • Your codebehind doesn't seem to be taking part in the problem stated in the question. – emerson.marini Sep 09 '14 at 18:52
  • @MelanciaUK I don't understand what you mean – user3929962 Sep 09 '14 at 19:01
  • Which part? I've updated the answer, now having all the Javascript/jQuery code within the document ready event handler - `$(function () { });`. And I don't believe you have an issue in your codebehind that could be messing up with this code - causing the Javascript error stated in your question. – emerson.marini Sep 09 '14 at 19:08
  • After you rolled back the changes, did you put back the classes in the DropDownLists? – emerson.marini Sep 09 '14 at 19:11
  • The updated JQuery does not run when the page is loaded.... meaning when I run the application and the page loads, ddlCity is blank. – user3929962 Sep 09 '14 at 19:13
  • 1
    Ah, sure. I've forgotten to add the call to the `populateSelect()`. Try the updated answer (just edited) again please. – emerson.marini Sep 09 '14 at 19:17
  • Ok, that your last response now works. I think I am at the last issue. When I change ddlState to a different value, ddlCity goes blank. That is where I think the codebehind is interrupting the JQuery. Would you agree? – user3929962 Sep 09 '14 at 19:24
  • It could be. Try to debug both codebehind and client-side to see step-by-step what's going on. – emerson.marini Sep 09 '14 at 19:28
  • well, when I set AutoPostBack = false, everything works perfectly. When I set it back to true, I run into the issue in my last comment – user3929962 Sep 09 '14 at 19:31
  • I am trying out this suggestion http://stackoverflow.com/questions/22510926/trigger-jquery-code-on-autopostback-true – user3929962 Sep 09 '14 at 19:32
  • This one might be helpful too: http://stackoverflow.com/questions/2203988/jquery-dropdown-selector-autopostback – emerson.marini Sep 09 '14 at 19:32
  • wow... I think that does it. Thanks very much for your help!! – user3929962 Sep 09 '14 at 19:55
  • No problems. I'm glad I could help. The thing is the `AutoPostBack` adds an `onchange` event handler to the `DropDownList`, and it was being broken by the jQuery call. If you return true, it will carry on normally. – emerson.marini Sep 09 '14 at 19:57
2

Never use eval. Store your data in an object instead:

var states = {
    'AL': ['Birmingham', 'Montgomery', 'Tuscaloosa'],
    'FL': ['Miami', 'FtLauderdale', 'Jacksonville'],
    'GA': ['Atlanta', 'Macon', 'Athens']
};

function populateSelect() {
    var category = $('#ddlState').val(); // selected state

    if (category && states[category]) {
        $('#ddlCity').html('');
        states[category].forEach(function (t) {
            $('#ddlCity').append('<option>' + t + '</option>');
        });
    } else {
        console.log('invalid state input: '+category); 
    }
}

$(function () {
    $('#ddlState').change(function () {
        populateSelect();
    });
    populateSelect();
});

I am assuming that the <asp:DropDownList> element does produce an HTML element with the specified ID.

sebnukem
  • 8,143
  • 6
  • 38
  • 48
  • then that means that the `category` value doesn't match any key in the `states` object. Check your value with a `console.log('state = '+category);` statement. – sebnukem Sep 09 '14 at 15:20