1
votes

In asp.net mvc (v5 in my case), when you post a model back to a controller, and then render a view with a model other than the one that was posted back, then Html.DropDownListFor will select the selected item based on the data from the model that was posted back, rather than the model that was passed to the view.

Why is this?

Here's an example. When you select a new item in the first dropdown, the form posts back, and if the fist dropdown has id=2 selected, then the selectedId2 is changed and the second dropdown should render with the second item selected. However that's not the case. While the Model object in the view does have the new selectedId2 = 2 value, the DropDownListFor under the hood gets the selected value from the ViewState.ModelState object, not the ViewState.Model. What can be done to get the DropDownListFor to render based only on the Model passed to the view?

The Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var defaultModel = getModel();
        return View(defaultModel);
    }

    [HttpPost]
    public ActionResult Index(Model1 postedModel)
    {
        var defaultModel = getModel();

        if (postedModel.selectedId1 == 2)
        {
            defaultModel.selectedId1 = 2;
            defaultModel.selectedId2 = 2;
        }

        return View(defaultModel);
    }

    private Model1 getModel()
    {
        var items1 = new[]
        {
            new
            {
                Name = "Item 1-1",
                Id = "1"
            },
            new
            {
                Name = "Item 1-2",
                Id = "2"
            }
        };

        var items2 = new[]
        {
            new
            {
                Name = "Item 1-1",
                Id = "1"
            },
            new
            {
                Name = "Item 2-2",
                Id = "2"
            }
        };

        return new Model1
        {
            selectedId1 = 1,
            selectedId2 = 1,
            SelectList1 = new SelectList(items1, "Id", "Name", 1),
            SelectList2 = new SelectList(items2, "Id", "Name", 1)
        };
    }


}

The View Model:

public class Model1
{
    public SelectList SelectList1 { get; set; }
    public SelectList SelectList2 { get; set; }
    public int selectedId1 { get; set; }
    public int selectedId2 { get; set; }
}

The View:

@model Model1

@using (Html.BeginForm(FormMethod.Post))
{
    <div>
        @Html.DropDownListFor(m => m.selectedId1, Model.SelectList1, new { title = "Select 1", onchange = "this.form.submit();" })
        @Html.DropDownListFor(m => m.selectedId2, Model.SelectList2, new { title = "Select 2", onchange = "this.form.submit();" })
    </div>
}

Edit: One Solution I found: Adding this line before executing the View() clears out the posted model so that the DropDownListFor helper uses the model that is passed to the view:

ViewData.ModelState.Clear();
1

1 Answers

1
votes

You can specify the selected value if you use the appropriate SelectList constructor:

SelectList Constructor (IEnumerable, String, String, Object)

The last parameter is the selected item, which must be one object of the IEnumerable.

You are using this constructor, but are specifying 1 as the value. It should be something like items1[0]