Quick hacks vs doing it right with MVC3 dropdowns

An obscure issue popped up today and it was a bit of a pain to track down. A user with IE6 (this is going to go on for YEARS) could not post a form back on a website because even though they selected a number from a dropdown list, it failed validation and told them that they 'must select a number'.

All the fancy javascript jQuery and unobtrusive data annotation validation was working, except for this glitch.

Now you can't just tell these people to upgrade their browsers (well, you can, but good luck with that) as they still represent a LOT of money in the marketplace, I'm talking about thousands of pounds a week for one site owner.

Luckily I keep a few virtual machines of XP with IE6 on them for just this and could see the same behaviour myself. The dropdown looks like this (in MVC3 Razor markup);

@Html.DropDownListFor(i => i.Quantity, new System.Web.Mvc.SelectList(new[] { 1, 2, 3, 4, 5 }, "Value", "Text", Model.Quantity), string.Empty, new { @class = "dish" })

This is a quick way to generate a dropdown list and populate it with a range of values. It outputs the following HTML;

<select class="dish valid" data-val="true" data-val-number="The field Quantity must be a number." id="SideDishes_1__Quantity" name="SideDishes[1].Quantity"><option value=""></option>
 <option selected="selected">1</option>

This looks OK to me and works in every other browser I've tried, but it seems that IE6 INSISTS on the 'value=1' field for each option. I would have expected the DropDownListFor method to output this anyway but if you bind to a simple list of native types (integers in this case) then you can't set the data field and the value field for the option element (an integer does not have properties, it just 'is').

To fix it, you need to go verbose in the code and do something similar to the following;

  var values = new[] { 1, 2, 3, 4, 5 }.Select(x => new System.Web.Mvc.SelectListItem
     Value = x.ToString(),
     Text = x.ToString()
  values = new System.Web.Mvc.SelectList(values, "Value", "Text", Model.Quantity);
@Html.DropDownListFor(i => i.Quantity, values, string.Empty, new {@class = "dish" })

Yes, it's ugly and I could make it a LOT better but it works. The option HTML output is now what IE6 expects;

<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>

I'm impressed by how compatible the jQuery team has made the validation so that it even works in IE and the only thing that broke was a false expectation of the dropdownlistfor method.

This bug took me a good hour to sort out with the Virtual Machines and testing, hope this post helps you sort it quicker. The workaround is from the following StackOverflow blog post on binding to integers

comments powered by Disqus

Ryan O'Neill

Mostly about tech, working for myself and my thoughts.

Ludlow, Shropshire, UK