Wednesday 19 October 2011

MVC 3 Html.DropDownList - How to Post Data back to an Action Method

To assign a Hazard to a Worksite Location, we need a drop down list (DDL) of Hazard Types to choose from.

By default, when you create the Controller/Views for the WORK_SITE_HAZARD type, ASP.Net MVC will define a SelectList of HAZARD_TYPE objects and throw it in the ViewBag so the Create.cshtml view can access it and assign it to a Html.DropDownFor …

            ViewBag.HAZARD_TYPE_ID = new SelectList(db.HAZARD_TYPES, "HAZARD_TYPE_ID", "HAZARD_TYPE_DESC");

Because I’m coming at ASP.Net MVC with fresh eyes, I couldn’t help but think: “this is stupid, this name implies that it is putting the ID of a single HAZARD_TYPE in the ViewBag”

So I renamed it to HAZARD_TYPES and updated the view so that the Html.DropDownFor would reference a collection called “HAZARD_TYPES”…makes much more sense!

However, when I then go to post the data back to the Create(WORK_SITE_HAZARD wsh) action method (which expects an instantiated WORK_SITE_HAZARD object) the HAZARD_TYPE_ID is not populated.

This is because the internals that instantiate the WORK_SITE_HAZARD object for me is, by convention, looking for an element on the form with id=”HAZARD_TYPE_ID”.

It doesn’t find this though because the Html.DropDownFor helper sets the ID of the resulting <select> element to be the string you give it in the constructor, the “Name” property – which I have changed to “HAZARD_TYPES” because it is more semantic.

The second convention is, when rendering the Html.DropDownFor, the framework will look in the ViewBag for any object with key equal to the string you pass as the “Name” parameter into the Html.DropDownFor constructor.

So if you were to change the name you pass into the Html.DropDownFor constructor, to say  ‘ddlHazardTypes’, you’ll get:

”There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'ddlHazardTypes'”

So, just before I was going to give into their, in my opinion, stupid convention: I found an overloaded version of the Html.DropDownFor constructor:

@Html.DropDownList("HAZARD_TYPE_ID", (SelectList)ViewBag.HAZARD_TYPES ,String.Empty, null)

This allows me to give the <select> element the an ‘id’ attribute of “HAZARD_TYPE_ID”, which the framework needs to instantiate the WORK_SITE_HAZARD object, populate it with the selected HAZARD_TYPE and pass it back to the Create action method

AND

ensure the list to which the DropDownList is bound, is called something meaningful, eg “HAZARD_TYPES”

No comments:

Post a Comment