Albert Tobing
Albert Tobing

Reputation: 169

MVC 5 DropDownListFor postback null

I am trying to create cascading dropdownlist using @Html.DropDownListFor helper and jQuery AJAX. The first load is always perfect. all dropdownlist data was displayed correctly. However, after postback, it always hit ModelState.IsValid = False and the dropdownlist become empty. Below is my code:

Model

Public Property Province As New List(Of SelectListItem)
Public Property City As New List(Of SelectListItem)
Public Property SelectedProvince As String
Public Property SelectedCity As String

Controller

Public Function SetEmployeeProfile() As ActionResult
    Dim loc As New clsLocation
    Dim provinces As List(Of Province)
    Dim model As New SetEmployeeProfileViewModel

    provinces = loc.GetProvinceList
    Dim sel As SelectListItem

    For Each p As Province In provinces
        sel = New SelectListItem
        sel.Text = p.ProvinceName
        sel.Value = p.ProvinceName
        model.Province.Add(sel)
    Next

    Return View(model)    

End Function

View

@ModelType SetEmployeeProfileViewModel

    <div class="form-group">
        @Html.LabelFor(Function(m) m.Province, New With {.class = "col-md-2 control-label"})
        <div class="col-md-10">
            @Html.DropDownListFor(Function(m) m.Province, New SelectList(Model.Province, "Value", "Text", Model.SelectedProvince), New With {.class = "form-control"})
            @Html.ValidationMessageFor(Function(m) m.Province, "", New With {.class = "text-danger"})
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(Function(m) m.City, New With {.class = "col-md-2 control-label"})
        <div class="col-md-10">
            @Html.DropDownListFor(Function(m) m.City, New SelectList(Model.City, "Value", "Text", Model.SelectedCity), New With {.class = "form-control"})
            @Html.ValidationMessageFor(Function(m) m.City, "", New With {.class = "text-danger"})
        </div>
    </div>


<script type="text/javascript">
$(document).ready(function () {
    LoadCities();
});

$("#Province").change(function () {
    LoadCities();
});

function LoadCities() {
    var selectedItem = $("#Province").val();
    var ddlCities = $("#City");
    var statesProgress = $("#city-loading-progress");
    statesProgress.show();
    $.ajax({
        cache: false,
        type: "POST",
        url: "@(Url.Action("GetCities"))",
        data: { "provinceName": selectedItem },
        success: function (data) {
            ddlCities.html('');
            $.each(data, function (id, option) {
                ddlCities.append($('<option></option>').val(option.CityName).html(option.CityName));
            });
            statesProgress.hide();
        },
        error: function (xhr, ajaxOptions, thrownError) {
            alert('Failed to retrieve cities.');
            statesProgress.hide();
        }
    });
}

NOTE: I tried adding selectedProvince property in the model and implemented according to this post but the problem still persist. Both Province and City field also produces the following validation error:

The value 'Bali' is invalid.  (Province)
The value 'Kuta' is invalid.  (City)

The URL after postback is: https://localhost:55500/Employee/SetEmployeeProfile?Sex=M&Dob=01%2F01%2F0001%2000%3A00%3A00&Province=System.Collections.Generic.List%601%5BSystem.Web.Mvc.SelectListItem%5D&City=System.Collections.Generic.List%601%5BSystem.Web.Mvc.SelectListItem%5D

Is it normal that it put query string: Province=System.Collections.Generic.List ?

Upvotes: 0

Views: 1270

Answers (1)

ekad
ekad

Reputation: 14614

Your mistake is here

@Html.DropDownListFor(Function(m) m.Province, New SelectList(Model.Province, "Value", "Text", Model.SelectedProvince), New With {.class = "form-control"})

and here

@Html.DropDownListFor(Function(m) m.City, New SelectList(Model.City, "Value", "Text", Model.SelectedCity), New With {.class = "form-control"})

The first parameter of @Html.DropDownListFor() for the first dropdownlist should be Function(m) m.SelectedProvince instead of Function(m) m.Province, and for the second dropdownlist should be Function(m) m.SelectedCity instead of Function(m) m.City.

Below is the changed portion of code:

<div class="form-group">
    @Html.LabelFor(Function(m) m.Province, New With {.class = "col-md-2 control-label"})
    <div class="col-md-10">
        @Html.DropDownListFor(Function(m) m.SelectedProvince, New SelectList(Model.Province, "Value", "Text", Model.SelectedProvince), New With {.class = "form-control"})
        @Html.ValidationMessageFor(Function(m) m.Province, "", New With {.class = "text-danger"})
    </div>
</div>

<div class="form-group">
    @Html.LabelFor(Function(m) m.City, New With {.class = "col-md-2 control-label"})
    <div class="col-md-10">
        @Html.DropDownListFor(Function(m) m.SelectedCity, New SelectList(Model.City, "Value", "Text", Model.SelectedCity), New With {.class = "form-control"})
        @Html.ValidationMessageFor(Function(m) m.City, "", New With {.class = "text-danger"})
    </div>
</div>

Upvotes: 1

Related Questions