MVC, DropDownLists and ViewModels

MVCThere are a number of resources out there that describe how to do DropdownLists in MVC. In my opinion, none of them gave me stable, re-usable code that I could implement. This is the way that I do dropdownlists so hopefully it will help some of you.

At its essence, I have a ViewModel that extends the base class. If you are using an ORM (like Entity Framework or NHibernate), then your classes would probably already be created when you updated your model from your database. Take this ViewModel as an example. Let's say the base class is called ViewModelEntity. We create another class called ViewModelEntityExtended. In our extended class, we have a field for the base entity. Then, we have three fields that are for the dropdownlist data.

public class ViewModelEntity
	public int Id { get; set; }
	public string Name { get; set; }
	public string Description { get; set; }	
	public int ForeignTableId { get; set; }		
public class ViewModelEntityExtended
	public ViewModelEntity entity { get; set; }

	//  Helpers
	public IEnumerable DropdownList1 { get; set; }
	public IEnumerable DropdownList2 { get; set; }
	public IEnumerable DropdownList3 { get; set; }

Then, in our action, we simply fill the fields with data from the ViewModelBuilder. If you have never used ViewModelBuilders before, they are simply a class that abstracts the data work from the action. There are many benefits of using builders like separation of code, code readability and better testing opportunities.

public ActionResult Create()
	ViewModelEntityExtended model = new ViewModelEntityExtended();
	// we can control the fields that used for the ID and Name fields of our SelectList
	model.DropdownList1 = new SelectList(_builder.GetAllDropdownList1Data(), "Id", "Name");
	model.DropdownList2 = new SelectList(_builder.GetAllDropdownList2Data(), "Id", "Name");
	model.DropdownList2 = new SelectList(_builder.GetAllDropdownList3Data(), "PrimaryId", "Description");
	return View(model);

Here is the builder method. Now, there are some extra lines of code in this method that relate to services and interfaces. I will cover this methodologies in another post, but the essence of this method is that it returns a typed list of data which the action puts into the ViewModel.

public class EntityViewModelBuilder : IEntityViewModelBuilder
	private readonly IServiceFacade _service;
	public EntityViewModelBuilder(IServiceFacade service)
		_service = service;
	// This is the key part that we are interested in
	public List GetAllDropdownList1Data()
		var DropdownList1Data = new List();
		var responseTypes = _service.GetAllDropdownList1Data();
		Mapper.Map(responseTypes.Result, DropdownList1Data);
		return DropdownList1Data;

So, now the action is populating our ViewModel. Let's create the view. The view will be bound to the ViewModelEntityExtended object and not the base class from your ORM. We need to do this so that we get the extra fields that now have our dropdownlist data. You can see from the below code that our DropdownList elements are still bound to the ViewModelEntity object, but are passing in additional parameters to the DropDownList method.

NB: We are using the DropDownList object, NOT the DropDownListFor object. The reason is because we want to pass in the data for the dropdownlist.

<div class="form-group">
	@Html.LabelFor(model => model.ForeignTableId, new { @class = "col-md-3"})
	<div class="col-md-9">
		@Html.DropDownList("ForeignTableId ", Model.DropdownList1, "Select an Item")
		@Html.ValidationMessageFor(model => model.ForeignTableId)

And that's it. There is a little theory there to get your head around, but the convention is quite simple.

Til next time ...