Murat
Murat

Reputation: 149

How to preserve cascading dropdownlist items after httppost if form has invalid ModelState

I have three dropdown (cascaded) in a View. First dropdown elements come from the ViewModel. I'm populating 2nd dropdown elements when 1st dropdown changes. and same for the 3rd dropdown. Classic cascading dropdownlist example you can find on anywhere (ex: http://www.c-sharpcorner.com/UploadFile/4d9083/creating-simple-cascading-dropdownlist-in-mvc-4-using-razor/ )

Problem occurs when user submits the form. If ModelState is invalid, 2nd and 3rd dropdown loses their items and 1st dropdown conserves its state. I understand why they behave like that but can't figure it out how to populate them again with the users selected values.

Scenario

  1. User request /Country/Index
  2. After page loaded, user selects CountryId DropDownList
    • Send Country Id to method and if result is not null, load StateId DropDownList.
  3. Do not fill PostalCode Textbox and submit form.
  4. Examine that CountryId DropDownlist is filled and selected but StateId ropdownlist is empty.
  5. Cry

View

//HTML Code
//...

@Html.DropDownListFor(m => m.CountryId, ViewBag.Country as IEnumerable<SelectListItem>, "Select Country")
@Html.DropDownListFor(m => m.StateId, new SelectList(string.Empty, "Value", "Text"), "Select State")
@Html.DropDownListFor(m => m.CityId, new SelectList(string.Empty, "Value", "Text"), "Select City")
@Html.TextBoxFor(m=> m.PostalCode)

<script type="text/javascript">
var countryDDL = $("#CountryId");
countryDDL.change(function () {
                $.ajax({
                    type: 'POST',
                    url: '@Url.Action("LoadStateList")',
                    dataType: 'json',
                    data: { countryId: countryDDL.val() },
                    success: function myfunction(states) {
                        $("#StateId").empty();
                        $.each(states, function (i, state) {
                            $("#StateId").append('<option value="' + state.Value + '">' + state.Text + '</option>');
                        }); }
                   });
                   return false;
                });

//Code for 2nd (state) dropdownlist.change() method.
//...
</script>

Controller

public ActionResult Index()
{
    ViewBag.CountryList = LoadCountryList();
    return View();
}

[HttpPost]
public ActionResult Index(CountryViewModel cvm)
{
    if(ModelState.IsValid)
    {
        //Save or do whatever you want
    }

    ViewBag.CountryList = LoadCountryList();
    return View();
}

View Model

public class CountryViewModel
{
    public int CountryId {get;set;}
    public int StateId {get;set;}
    public int CityId {get;set;}

    [Required]
    public string PostalCode {get;set;}
}

Upvotes: 3

Views: 1756

Answers (1)

Chris Pratt
Chris Pratt

Reputation: 239400

The actual select options are not posted (nor should they be). Therefore, when you get to the post action, your select list is empty. The solution? Simply repopulate it the same as you would in your get action. Granted, here, you're not populating those in the get action, but rather retrieving them via AJAX. You could technically do it the same way on post, if you wanted. You'd just have to run the AJAX calls on page load to refetch the select lists. However, it would be much better at this point to just do it in your post action.

Upvotes: 2

Related Questions