tags:

views:

3311

answers:

7

Hi,

I have an editor template for a custom object. Inside that editor template I use a couple of DropDownListFor helpers. In each of them I specify a unique model property (with the pre-selected value) and the select list containing all the select options.

Example:

<%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>

I know that the option values are being populated (from viewing source) and that my Model is passed in with the correct ID value (DocumentCategoryType).

When the view is rendered, there is no selected item in my dropdown and therefore it defaults to the first (non-selected) value.

Does anyone have any ideas?

Thanks.

A: 

Please also post your DropDownListFor method...

Anyway, if you're using the SelectList object, you can ( in the constructor ) specifiy the default value ( http://msdn.microsoft.com/en-us/library/dd492553.aspx )

David
dont know why they marked you down. guess this should be a comment though
burnt_hand
+3  A: 

It is confirmed as a bug @ aspnet.codeplex.com and only behaves like this for strongly typed views.

Workaround: populate your SelectList in the view code

like

<%= Html.DropDown("DocumentCategoryType", new SelectList(Model.Categories,"id","Name",Model.SelectedCategory")) =>
Alexander Taran
That makes sense. I would have REALLY liked to have been able to do all of this in my model before passing in. Hopefully they catch this and fix it before RTM. Do you happen to have a link to the bug?
kmehta
dunno about the actual bug link, but this problem is also discussed here in the forums at the asp.net site:http://forums.asp.net/p/1528524/4049618.aspx#3840473
kdawg
A: 
Model.DocumentCategoryTypeList

This is probably your problem. On the SelectListItems, do you set the value to the .ToString() output?

 var list = new List<SelectListItem>()
                           {
                               new SelectListItem()
                                   {
                                       Value = Category.Book.ToString(),
                                       Text = "Book"                                     
                                   },
                               new SelectListItem()
                                   {
                                       Value = Category.BitsAndPieces.ToString(),
                                       Text = "Bits And Pieces"                            },
                               new SelectListItem()
                                   {
                                       Value = Category.Envelope.ToString(),
                                       Text = "Envelopes"                              }
                           };

Works for me after doing that. It just needs to be able to match the value from the object

burnt_hand
thanks, all of my values and the model property to be bound to are all strings already.
kmehta
can you put the code up for the DocumentCategoryTypeList
burnt_hand
Just realised that the dropdown was in the view so I was wrong. I changed to the EditorTemplate and it stopped working.
burnt_hand
A: 

Yuck. I ended up solving it like this. I hope this gets fixed for RTM.

   <%if(Model!=null){ %>
        <%= Html.DropDownListFor(m => m.DocumentCategoryType, new SelectList(Model.DocumentCategoryTypeList,"Value","Text", Model.DocumentCategoryType))%>
        <%}else{%>
            <%=Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList) %>
        <%}%>
kmehta
Nope, the bug is still there. A pretty stupid one, too. What happened to dogfooding?
Thomas Eyde
+3  A: 

We also solved the solution by populating a new SelectList that has the appropriate SelectListItem selected, but created this extension method to keep the call to DropDownListFor a little cleaner:

public static SelectList MakeSelection(this SelectList list, object selection)
{
    return new SelectList(list.Items, list.DataValueField, list.DataTextField, selection);
}

Then your DropDownListFor call becomes:

<%= Html.DropDownListFor(m => m.DocumentCategoryType, Model.DocumentCategoryTypeList.MakeSelection(m.DocumentCategoryType)) %>
itsmecurtis
This worked for me
Andiih
+2  A: 

Looking through the ASP.NET MVC 2 source code reveals some solutions to this problem. Essentially, any SelectListItem in the SelectList passed in the helper extension method that has the Selected property set to true does not have any bearing over the <option> element rendered with the selected attribute applied for the item.

The selected attribute on <option> elements is determined by

1) checking that the helper extension method was passed a SelectList. If this is null, the framework will look in the ViewData for a value corresponding to the key that is the view model property for which you wish to render the drop down list for. If the value is a SelectList, this will be used to render the <select> including taking any selected values, so long as the model state for the model property is null.

2) If a SelectList has been passed in the helper extension method and the model state for the model property is null, the framework will look in the ViewData for a default value, using the model property name as the key. The value in view data is converted to a string and any items in the SelectList passed to the helper extension method that have a value (if no value is set, then the Text will be checked) that matches the default value will have the Selected property set to true which in turn will render an <option> with the attribute selected="selected".

Putting this together, the most straightforward way that I can see to have an option selected and use the strongly typed DropDownListFor is to set a value in the ViewData in the controller rendering your view. For example

the view model

public class CategoriesViewModel
{
    public string SelectedCategory { get; private set ; }
    public ICollection<string> Categories { get; private set; }

    public CategoriesViewModel(string selectedCategory, ICollection<string> categories)
    {
        SelectedCategory = selectedCategory;
        Categories = categories;
    }
}

the controller action

public class CategoriesController
{
    [HttpGet]
    public ViewResult Select()
    {
        /* some code that gets data from a datasource to populate the view model  */
        ICollection<string> categories = repository.getCategoriesForUser();
        string selectedCategory = repository.getUsersSelectedCategory();

        CategoriesViewModel model = new CategoriesViewModel(selectedCategory, categories);
        this.ViewData["Categories"] = selectedCategory;        

        return View(model);
    }

    [HttpPost]
    public ActionResult Select(CategoriesViewModel model)
    {
        /* some code that does something */
    }
}

and in the strongly typed view

<%: Html.DropDownListFor(m => m.Categories, m.Categories.Select(c => new SelectListItem { Text = c, Value = c }), new { @class = "my-css-class" }) %>
Russ Cam
A: 

I managed to solve the same problem by saying the folling:

new SelectList(sections.Select(s => new { Text = s.SectionName, Value = s.SectionID.ToString() }), "Value", "Text")

This trick is converting to the value to a string. I know this has been mentioned in previous answers but i find my solution a little cleaner :). Hope this helps.

nfplee