Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selected property in SelectListItem never works (DropDownListFor)

I have problems when selecting a value of a DropDownList. I've been reading all the similar posts and I can't get a solution.

The actual approach seemed very good to me, because I can inspect the fields that will be inside the SelectList:

var selectList = new List<SelectListItem>(
    from variable in someKindOfCollection
    select new SelectListItem
        {
            Selected = variable.Property == selection,
            Text = variable.Property,
            Value = variable.Property
        });

Supposedly, this gives me total control. After the selectList has been built I can inspect the variables with the debugger. Everything is OK and one of them has the "Selected" attribute marked.

Then I use DropDownListFor in order to show on the view:

@Html.DropDownListFor(
    g => g.SomePropertyInModel , selectList, new { @class = "cssClass" })

But It doesn't work, never... "Renders" the dropdown, but nothing is selected.

Thanks a lot :)

NEW EXAMPLE First of all I want to apologize. I've been hiding information, of course totally unintentionally. All the code happens inside a Razor For Loop:

@foreach (var loopVariable in Model.Collection)
{
    if (Model.SomeCondition != null)
    {
        selection = someValue;
    }

    var selectList = new List<SelectListItem>(
      from variable in someKindOfCollection
      select new SelectListItem
    {
        Selected = variable.Property == selection,
        Text = variable.Property,
        Value = variable.Property
    });

    @Html.DropDownListFor(
        g => g.SomePropertyInModel , selectList, new { @class = "cssClass" })

}

So, It's the fact of selectList is a local variable causing the behavior?. Sorry, I didn't thought it was that.

like image 723
Jacob Avatar asked Mar 20 '12 18:03

Jacob


1 Answers

I think you are having the same problem i did. I looked through the source code to find my solution and it appears this is a bug to me. The following DropDownListFor should help, the key to it is that you pass the selected value into the html helper. Hope this helps.

public static class SelectExtensions {
    public static IHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItem> selectList, string selectedValue, string optionLabel, object htmlAttributes = null) {
       return DropDownListHelper(helper, ExpressionHelper.GetExpressionText(expression), selectList, selectedValue, optionLabel, htmlAttributes);
    }

    /// <summary>
    /// This is almost identical to the one in ASP.NET MVC 3 however it removes the default values stuff so that the Selected property of the SelectListItem class actually works
    /// </summary>
   private static IHtmlString DropDownListHelper(HtmlHelper helper, string name, IEnumerable<SelectListItem> selectList, string selectedValue, string optionLabel, object htmlAttributes) {
        name = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

        // Convert each ListItem to an option tag
        var listItemBuilder = new StringBuilder();

        // Make optionLabel the first item that gets rendered
        if (optionLabel != null)
            listItemBuilder.AppendLine(ListItemToOption(new SelectListItem() { Text = optionLabel, Value = String.Empty, Selected = false }, selectedValue));

        // Add the other options
        foreach (var item in selectList) {
            listItemBuilder.AppendLine(ListItemToOption(item, selectedValue));
        }

        // Now add the select tag
        var tag = new TagBuilder("select") { InnerHtml = listItemBuilder.ToString() };
        tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        tag.MergeAttribute("name", name, true);
        tag.GenerateId(name);

        // If there are any errors for a named field, we add the css attribute
        ModelState modelState;

        if (helper.ViewData.ModelState.TryGetValue(name, out modelState)) {
            if (modelState.Errors.Count > 0)
                tag.AddCssClass(HtmlHelper.ValidationInputCssClassName);
        }

        // Add the unobtrusive validation attributes
        tag.MergeAttributes(helper.GetUnobtrusiveValidationAttributes(name));

        return tag.ToHtmlString(TagRenderMode.Normal);
    }

    private static string ListItemToOption(SelectListItem item, string selectedValue) {
        var tag = new TagBuilder("option") { InnerHtml = HttpUtility.HtmlEncode(item.Text) };

        if (item.Value != null)
            tag.Attributes["value"] = item.Value;

        if ((!string.IsNullOrEmpty(selectedValue) && item.Value == selectedValue) || item.Selected)
            tag.Attributes["selected"] = "selected";

        return tag.ToString(TagRenderMode.Normal);
    }
}
like image 121
nfplee Avatar answered Sep 21 '22 03:09

nfplee