DropDownListFor not selecting the selected item in the SelectList

asp.net-mvc, asp.net-mvc-3, html.dropdownlistfor, selectlist

Solution

Generally, the `Selected` property in `SelectList` will be totally ignored by the HTML helpers unless there's no other option. If `DropDownListFor` can find the value by other means, it will insist on using that value.

In this case, it will use the value of `model.PersonType`(`.ToString()`) - but that's not what you want, judging by the `model.PersonType.ID` you pass to the `SelectList`.

More info in the answer here.

Workaround

One easy workaround that should work would be to set:

ViewData["PersonType"] = model.PersonType.Id. 

The helper looks in ModelState first if it exists - i.e. on POST. This should work already, since `ModelState["PersonType"]` will be populated with the actual selected value that was posted.

After ModelState it will look in `ViewData` - with `ViewData["PersonType"]` first, and only then `ViewData.Model.PersonType`. In other words, you can "override" the value on your model with a value set directly on `ViewData`.

Better (IMO) solution

The more general, "better practice", way to solve it (which also avoids having a custom model binder in order to translate the POST'ed ID back to `PersonType`) is to use a ViewModel instead of working with full models in your view:

- Have a `PersonTypeID` property - instead of `PersonType`.

- Populate it with `PersonType.ID`

- use this in your view

- VB.NET: `Html.DropDownListFor(Function(model) model.PersonTypeID)`, or

- C#: `Html.DropDownListFor(model => model.PersonTypeID)`

- When form is POST'ed, translate the ViewModel (including `PersonTypeID` => `PersonType`) back into the actual model in your POST Action.

This may seem like more work, but generally there tend to be many occasions in a project where you need more view-specific representations of your data to avoid too much inline Razor code - so translating from business objects to view models, while it may seem redundant and anti-DRY at times, tends to spare you of a lot of headaches.

Problem

I am working on an ASP.NET MVC3 application and I cannot get a DropDownListFor to work with my property in a particular editor view. My model is a `Person` and a person has a property that specifies it's "Person Type". `PersonType` is a class that contains a name/description and an ID. I can access the available `PersonType`s within the application through my static/shared class called `ApplicationSettings`. In the Edit Template view for my `Person` I have created a `SelectList` for debugging purposes: ``` @ModelType MyNamespace.Person @Code Dim pTypesSelectList As New SelectList(MyNamespace.ApplicationSettings.PersonTypes, "ID", "Name", Model.PersonType.ID) End Code ``` I am then providing this `SelectList` as a parameter to the `DropDownListFor` that is bound to the `PersonType` property of my `Person`. I am also printing the `Selected` property of each item in the `SelectList` for debugging purposes: ``` <div style="text-align: center; margin: 5px 0 0 0;"> <div> @Html.LabelFor(Function(model) model.PersonType) </div> <div> @Html.DropDownListFor(Function(model) model.PersonType, pTypesSelectList) @Html.ValidationMessageFor(Function(model) model.PersonType) <br /> <br /> <!-- The following is debugging code that shows the actual value--> @Model.Type.Name <br /> @Model.Type.ID <br /> <br /> <!--This section is to show that the select list has properly selected the value--> @For Each pitem In pTypesSelectList @<div> @pitem.Text selected: @pitem.Selected </div> Next </div> </div> ``` The view is bound to a `Person` whose `PersonType` property is "Person Type # 2" and I expect this to be selected; however the HTML output of this code looks like this: ``` <div style="text-align: center; margin: 5px 0 0 0;"> <div> <label for="PersonType">PersonType</label> </div> <div> <select id="PersonType" name="PersonType"> <option value="7e750688-7e00-eeee-0000-007e7506887e">Default Person Type</option> <option value="87e5f686-990e-5151-0151-65fa7506887e">Person Type # 1</option> <option value="a7b91cb6-2048-4b5b-8b60-a1456ba4134a">Person Type # 2</option> <option value="8a147405-8725-4b53-b4b8-3541c2391ca9">Person Type # 3</option> </select> <span class="field-validation-valid" data-valmsg-for="PersonType" data-valmsg-replace="true"></span> <br /> <br /> <!-- The following is debugging code that shows the actual value--> Person Type # 2 <br /> a7b91cb6-2048-4b5b-8b60-a1456ba4134a <br /> <br /> <!--This section is to show that the select list has properly selected the value--> <div> Default Person Type selected: False </div> <div> Person Type # 1 selected: False </div> <div> Person Type # 2 selected: True </div> <div> Person Type # 3 selected: False </div> </div> </div> ``` As you can see the printed Selected properties for the items in the SelectList shows that the 3rd item is "Selected". But what is driving me crazy is that the option that corresponds with this is Not Selected.

Original source

Related problems