ASP.NET MVC SelectList selectedValue Gotcha

by Ben Hart 24. November 2008 13:14

A recent post from Ayende was declaring a another bug in ASP.NET MVC, specifically referring to a select not rendering with the option selected. I remembered that we had had some issues some time ago, and had made our own helper to render selects, and took the opportunity to see whether we had made the same incorrect assumption - passing in the whole object, when only the value field was required.

I think we might have, but chatting to the team some other problems were experienced. It seemed the selected value was working in some situations, but not all. To keep as simple as possible, I used a test class similar to Ayende's:

public class IdName
{
    public int Id { get; set; }
    public string Name { get; set; }
}

And built a SelectList as duly instructed by the commentators on the post:

var list = new[] 
{   
    new IdName { Id = 1, Name = "Name1" }, 
    new IdName { Id = 2, Name = "Name2" }, 
    new IdName { Id = 3, Name = "Name3" } 
};
var selectList = new SelectList(list, "Id", "Name", 2);
ViewData["TestClasses"] = selectList;

Using the following extension method on the view

Html.DropDownList("TestClass", (SelectList)ViewData["TestClasses"])

this all works as expected:

<select id="TestClass" name="TestClass">
    <option value="1">Name1</option>
    <option selected="selected" value="2">Name2</option>
    <option value="3">Name3</option>
</select>

I noticed, though, that this was not working for all our views. Despite exactly the same pattern, many of our views weren't rendering the selected attribute.

At some point long ago we built our own binding framework that reflect items and passes found values through. Thus often we have a referenced object which is passed through to the view, and we there have a few helpers that get id's and appropriate 'names'. At the time this seemed fine, in retrospect we've painted ourselves into a corner. If we modified the above snippet to something along the lines of:

var list = new[] 
{   
    new IdName { Id = 1, Name = "Name1" }, 
    new IdName { Id = 2, Name = "Name2" }, 
    new IdName { Id = 3, Name = "Name3" } 
};
var selectList = new SelectList(list, "Id", "Name", 2);
ViewData["TestClasses"] = selectList;
ViewData["TestClass"] = 3;

The select does not render with the option passed in to the SelectList as the selectedValue, but rather uses what is found in ViewData with the same name as the select.

<select id="TestClass" name="TestClass">
    <option value="1">Name1</option>
    <option value="2">Name2</option>
    <option selected="selected" value="3">Name3</option>
</select>

If what is in ViewData does not correspond to the value, nothing is selected. I played around with this for much longer than I should have before investigating the beta source, which has the following block in SelectExtensions.SelectInternal():

// If we haven't already used ViewData to get the entire list of items then we need to
// use the ViewData-supplied value before using the parameter-supplied value.
if (!usedViewData) {
    object defaultValue;
    if (htmlHelper.ViewData.TryGetValue(name, out defaultValue)) {
        selectList = new MultiSelectList(selectList.Items, selectList.DataValueField, selectList.DataTextField,
            (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue });
    }
}

The RenderDropDown above eventually calls this method passing in false for usedViewData, and as such the above is always executed. Thus no matter what is passed in to the selectedValue of the SelectList, it will always be overridden by any object in ViewData with the same name as the select.

Now that I understand what's happening it's a little easier to bear. I also acknowledge that one could (even should) adopt a practice of ensuring that the object in ViewData with the same key as the desired name of a select should contain value to be marked selected.

But still, if I've gone to the effort to set the selectedValue in the SelectList, I'd prefer it to take precedence.

Technorati Tags:

Currently rated 4.2 by 5 people

  • Currently 4.2/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

ASP.NET MVC

Comments

Add comment


(Will show your Gravatar icon)  

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen

About me...

I'm a passionate .NET developer, with C# my language of choice. I've been at it for a number of years now, and enjoy that I'll never shake the feeling I'm just starting out.

I love software, and I love building it even more. I love knowing that my work facilitates others', and that one line of code at a time, we're increasing our capability.

More...



Page List