ASP.NET MVC: DropDownListFor doesn't select any option
Asked Answered
A

2

5

I have this to populate a drop down list in an ASP.NET MVC view.

<%= Html.DropDownListFor(model => model.Bikes,
      Model.Bikes.Select(
      x => new SelectListItem {
               Text = x.Name,
               Value = Url.Action("Details", "Bike", new { bikeId = x.ID }),
               Selected = x.ID == Model.ID,
           })) %>

Debugging this I can see that the Selected property is set to true when it should be. But when the view is rendered, none of the options in the list is selected. I realize that this could be done with another overload of DropDownListFor but I really want to get this version working.

Any ideas?

Aubrette answered 28/7, 2010 at 11:30 Comment(0)
O
5

The reason your selected value doesn't work is because you are using Urls as option values but specifying Model.ID in the Selected clause.

Try like this:

<%= Html.DropDownListFor(
    model => model.Bikes,
    new SelectList(Model.Bikes, "Id", "Name", Model.ID)
)%>

"Id" indicates the property that will be used as option value while "Name" indicates the property that will be used as option label.

If you want to preserve the Url.Action you could try:

<%= Html.DropDownListFor(
    model => model.Bikes,
    new SelectList(Model.Bikes.Select(x => new {
        Id = x.Id,
        Name = Url.Action("Details", "Bike", new { bikeId = x.ID })
    }), "Id", "Name", Model.ID)
)%>

You will notice that I've inverted the Name and Id as it seemed more logical to use the model Id as option value.


UPDATE:

The reason this doesn't work is because you are binding to an IEnumerable (the first argument of the DropDownListFor helper). It should be a scalar property while you are using the same model.Bikes collection:

<%= Html.DropDownListFor(
    model => model.SelectedBikeValue,
    Model.Bikes.Select(
        x => new SelectListItem {
                 Text = x.Name,
                 Value = Url.Action("Details", "Bike", new { bikeId = x.ID }),
                 Selected = x.ID == Model.ID,
        }
)) %>

My remark about not using Urls as option values stands true.

Orthoptic answered 28/7, 2010 at 11:33 Comment(4)
Note that in my original question the values are URLs.Aubrette
Yes, I've noticed this, but as this seemed to me a bad idea I've inverted them. By the way that's the reason why your selected value doesn't work. You are passing Model.Id as selected values and using urls as option values. No good. I would recommend you preserving the ID as option value and if necessary fetch the corresponding URL in the controller action you are submitting to. I don't see reasonable to use urls as option values.Orthoptic
In my original code I'm not passing IDs as selected values and URLs as option values. What I'm doing is setting the values to URLs and then using a condition which should hold for the item to be selected. And is there really any compelling reason as to why I should not be using URLs for values?Aubrette
Looking at the source code of DropDownList (or specifically SelectInternal) in .NET Reflector it's unclear to me whether the Selected property is meant to be set by the user or not. It does seem like it has no effect, so I guess I'll just have to forget about it. Thanks for your patience.Aubrette
D
0

I've had so many troubles with this concept. It especially manifests itself when you cannot pass it "name" property from the model that contains that property in an object, because such object name is automatically prepended to the name. This is crazy. After wasting many hours trying to figure this one out I just gave up and wrote my own Drop-Down extension which I publish here. It is very simple and it works just fine.

    public static MvcHtmlString SimpleDropDown(this HtmlHelper helper, object attributes, IEnumerable<SelectListItem> items, bool disabled = false)
    {
        XElement e = new XElement("select",
            items.Select(a => {
                XElement option = new XElement("option", a.Text);
                option.SetAttributeValue("value", a.Value);
                if (a.Selected)
                    option.SetAttributeValue("selected", "selected");
                return option;
            })
            );

        if (attributes != null)
        {
            Dictionary<string, string> values = (from x in attributes.GetType().GetProperties() select x).ToDictionary(x => x.Name, x => (x.GetGetMethod().Invoke(attributes, null) == null ? "" : x.GetGetMethod().Invoke(attributes, null).ToString()));
            foreach(var v in values)
                e.SetAttributeValue(v.Key, v.Value);
        }

        if (disabled)
            e.SetAttributeValue("disabled", "");

        return new MvcHtmlString(e.ToString());
    }

Also, I put flag disabled as an extra parameter, because if you want to bind to it via the standard anonymous list of attributes, it can be quite a hassle.

Below is an example of how I use it at the moment. I translate a dictionary into a list of SelectListItem, but it can be just a simple list.

@Html.SimpleDropDown(new { id="EOM", name = "EOM", @class = "topBox" }, Model.EOM.Select(x => new SelectListItem { Text = x.Value, Value = x.Key.ToString(), Selected = Model.EOM.Selected == x.Key }), !Model.EOM.Available)
Djebel answered 20/9, 2013 at 12:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.