views:

37

answers:

1

I have a form with a dropdownlist rendered using Html.DropDownListFor(...). The view model field that corresponds with the dropdown list has a [Required(...)] attribute attached to it. This works fine on my local machine, but as soon as I publish to our development server, the drop down lists keep displaying the required error message, even when a value is selected in the list. This only happens in IE - Firefox submits just fine.

Any thoughts?

Relevant code

View:

<ol class="form">
    <li>
        <%= Html.LabelFor(x => x.ContactTitle) %>
        <%= Html.DropDownListFor(x=>x.ContactTitle, Model.GetTitleOptions()) %>
        <%= Html.ValidationMessageFor(x => x.ContactTitle) %>
    </li>
    <!-- more fields... -->
</ol>

View Model:

[Required(ErrorMessage = "Title is required")]
[DisplayName("Title")]
public string ContactTitle { get; set; }

// ...

public SelectList GetTitleOptions()
{
    return new SelectList(new string[] 
    {
        "","Dr.", "Mr.", "Ms.", "Mrs.", "Miss"
    });
}

It's all pretty basic stuff... I'm at a loss.

Edit: Just discovered this bug is limited to IE 8 compatibility view (and maybe prior versions). IE 8 in standards mode works as expected...

A: 

Chalk this one up to stupidity. The code in the example produces output similar to the following:

<select>
    <option></option>
    <option>Dr.</option>
    <option>Mr.</option>
    <option>Ms.</option>
    <option>Mrs.</option>
    <option>Miss</option>
</select>  

And the relevant MVC validation function (when a RequiredAttribute is applied to a property that corresponds to a drop down list) is:

Sys.Mvc.RequiredValidator._validateSelectInput = function Sys_Mvc_RequiredValidator$_validateSelectInput(optionElements) {
    /// <param name="optionElements" type="DOMElementCollection">
    /// </param>
    /// <returns type="Object"></returns>
    for (var i = 0; i < optionElements.length; i++) {
        var element = optionElements[i];
        if (element.selected) {
            if (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(element.value)) {
                return true;
            }
        }
    }
    return false;
}

Notice the function checks element.value. In the case of the html above, the value attribute is empty because there is no value attribute on the option elements. Therefore, the validation function returns false and the error occurs. This only appears to happen in IE <8, presumably because other browsers by default assign an option element's text to the value attribute if none is specified.

The solution was to modify the way I was returning the select list items from which the drop down list was built like so:

public IEnumerable<SelectListItem> GetTitleOptions()
{
    return BuildSelectListItems(new string[] 
    {
        "","Dr.", "Mr.", "Ms.", "Mrs.", "Miss"
    });
}

private List<SelectListItem> BuildSelectListItems(IEnumerable<string> values) {
    return (from v in values
            select new SelectListItem()
            {
                Text = v,
                Value = v
            }).ToList();
}

This results in the much more predictable HTML output:

<select>
    <option value=""></option>
    <option value="Dr.">Dr.</option>
    <option value="Mr.">Mr.</option>
    <option value="Ms.">Ms.</option>
    <option value="Mrs.">Mrs.</option>
    <option value="Miss">Miss</option>
</select>

which of course the function validates properly.

Chris