R – DropDownList SelectedValue not binding properly

asp.net-mvcdata-bindingdrop-down-menu

I have a DropDownList populated with a SelectList generated from (an anonymous type) that has two properties "CountryId" (int) and "Description" (string). I want the selected country in the list to be the defaultCountry.

Countries = new SelectList(countries, "CountryId", "Description", defaultCountry.CountryId);

where "countries" is an IQueryable of anonymous types from a Linq query. Countries is a public property on a view model:

public class CountryBaseViewModel
{
     public SelectList Countries { get; set; }
     public Contact Contact { get;set; }
     ....
}

The HTML looks like this:

<p>
<label for="CountryId">Home Country:</label>
<%= Html.DropDownList("CountryId", Model.Countries)%>
</p>

This is fine and when I load the page, the correct country is selected.

But when I submit the change to the Edit method on the controller, the binding seems to fail.

For example, when I use the following HTML

<p>
<label for="Contact.Job">Job/Post:</label>
<%= Html.TextBox("Contact.Job", Model.Contact.Job) %>
</p>

And I call the method

public ActionResult Create(Contact contact)

on the controller, then the contact.Job value is correctly filled in from the TextBox but the CountryId is not.

I presume MVC uses the "Contact.Job" (TextBox 1st) parameter to set this. But the first parameter of the DropDownList is "CountryId" not "Contact.CountryId" because if it is, then the selected value is not shown in the list when I load it.

It looks like the first parameter of TextBox is for data binding and the first parameter of DropDownList is to Find the selected item.

How do I use this style of data binding to get to the selected value I want in the DropDownList and then tie that to Model.Contact.Country?

Best Answer

You have to bind the selected value from the drop down list manually, doing the lookup for whichever entity you actually need to bind to in your controller action that gets called on the POST. You can either use a strongly typed value in your ViewModel as you suggested in your second post, or you can lookup the value of the drop down list in the ViewData bag.

So, you have most everything in place, but in your controller action that handles the POST, you'll want to get the value of the drop down list, load the entity associated with that value, then attach that entity to the object you're trying to update. Depending on your architecture, it's often just a simple call to a repository or data access service. You would do that manual binding prior to persisting the changes for the main object you're working with.