MVC 5 Drop Down Lists

The Rub

I mentioned in my last post about the heartbleed vulnerability that I had been working with the Microsofts MVC 5 framework. MVC is one of those frameworks I’ve tried to come to terms with previously but never really had a reason to actually learn the in’s, out’s and why’s… though recently I did receive a compelling demonstration from a Microsoft employee and decided that I would have to give Microsoft’s flavour a shot while I was upgrading one of my employers applications.

I have to say that I’m reasonably happy with how it all hangs together and how much easier it makes templating information for web applications. With that said though there are some things that seem almost counter-intuitive or just don’t work in the way that you expect them too. Today I wanted to touch on Drop Down Lists… because something that feels like it should be absurdly easy turned out to be absurdly confounding and wasted more of my time than I would care to admit.

I’ll be giving this example in VB.NET because although it’s not a very syntactically pretty language, VB5 was the first language I ever learned and there’s a kind of nostalgic stockholm syndrome that grips me whenever I’m writing Windows apps.

Drop Down Listing

I’m going to be talking about \@HTML.DropDownList instead of \@HTML.DropDownListFor because I need it for the project that I’m working on but hopefully the concepts are transferable enough. This will also be an incredibly simple example just focusing on the View and the Model, you may wish to populate your list from the Controller or ViewModel as your needs may be.

Below is some sample code for a View with a Drop Down List that will retrieve it’s values from and post back to a model:

@Code
  ViewData("Title") = "DDLTest"
End Code

<h2>DDLTest</h2>

@Using (Html.BeginForm("DDLTest", "Home", FormMethod.Post, Model))
  @Html.AntiForgeryToken()
  @<div class="form-group">
    <label for="txtThings">Drop Down List:</label>
    @Html.DropDownList("AThing", DirectCast(Model.ManyThings, SelectList), "blerg", New With {Key .[class] = "form-control", Key .[id] = "txtThings"})
    @Html.ValidationMessage("AThing")
  </div>
  @<div class="form-group">
    <input id="btnSubmit" type="submit" class="btn btn-primary" value="Save"/>
  </div>
End Using

In the example above you will see that the @HTML.DropDownList we’re creating has four fields that I’m assigning, the first two are the most important of these for this example as they constitute the post back property and list property in our model.

In our model we will have a property called AThing which matches the first field from the drop down list declaration and when this form is posted the value of the drop down list will be bound to that property of the model. When the view loads if the AThing property is already defined and matches a list item it will auto-magically set that to the selected list item.

The second field tells the drop down list where it needs to retrieve the list information from, in the case of this example it will be a property of the model. You will notice when you look at the Model example below that despite ManyThings being declared as a SelectList in our model, when it’s stored in the special Model variable that gets sent to the view it gets cast as a generic collection, so we need to tell it to convert it back to a SelectList.

The third and fourth field are less important for this example of how stuff works, the third field contains the default display option of the drop down list and the fourth field has the HTML properties of the drop down list.

Next lets have a look at the model.

Public Class DDLTestModel
  Private _AThing As String

  Public Property AThing As String
    Get
      Return _AThing
    End Get
    Set(value As String)
      _AThing = value
    End Set
  End Property

  Public ReadOnly Property ManyThings As SelectList
    Get
      Dim ThingList As New List(Of SelectListItem)
      Dim Thing1 As New SelectListItem
      Dim Thing2 As New SelectListItem
      Dim Thing3 As New SelectListItem

      Thing1.Text = "Thing1 Text!"
      Thing1.Value = "Thing1Val"
      ThingList.Add(Thing1)

      Thing2.Text = "Thing2 Text!"
      Thing2.Value = "Thing2Val"
      ThingList.Add(Thing2)

      Thing3.Text = "Thing3 Text!"
      Thing3.Value = "Thing3Val"
      ThingList.Add(Thing3)

      Dim ThingSelectList As New SelectList(ThingList, "Value", "Text")
      Return ThingSelectList
    End Get
  End Property
End Class

You will notice that we have a private variable _AThing for storing the value of the selected drop down list and more importantly the AThing public property that the drop down list binds to for getting and setting. If AThing is defined and matches an option from the ManyThings list when the view is loaded it will set that to the selected option in the drop down list.

Our second property on the model is the SelectList that will contain the items we want to display in the drop down list. In this example I am using a List of SelectListItem’s but you can realistically use any kind of property driven collection.

You will see that right at the end of the property declaration I create a New SelectList and provide the constructor with three different pieces of information. The first piece of information is the variable containing the collection we want to make our list from, the second piece is the name of the property on that collection that will be mapped to the value of each item in the drop down list and last but not least the third piece of information is the name of the property that will be mapped to the display text in the drop down list.

If you do happen to use a List of SelectListItem’s you will notice that SelectListItem has a property called “Selected”, you will also notice that if you try to use it that it doesn’t do anything. To set a default value you must ensure that the bound property for the drop down list is populated with the value of whichever list item you want it to default to.

Last of all for the sake of completeness here is a Controller that will let you try this out for yourself in a simple MVC application.

Public Class HomeController
  Inherits System.Web.Mvc.Controller

  Function DDLTest() As ActionResult
    Dim TestModel As New DDLTestModel
    Return View(TestModel)
  End Function

  <HttpPost> <ValidateAntiForgeryToken> Function DDLTest(ByVal TestModel As DDLTestModel) As ActionResult
    Return View(TestModel)
  End Function
End Class

That’s more or less all there is to setting up a simple drop down list… it’s all rather straight forward once you get it working but trying to divine this stuff on your own can be head scratching stuff. Hopefully this saves some one else the time that I lost!

comments powered by Disqus