tags:

views:

71

answers:

2

I know others have asked this question, but I'm totally confused by this:

This displays the dropdown with no values selected:

<%= Html.DropDownList("items", new MultiSelectList(Model.AvailableItems,
    "id", "name", Model.items), new { multiple = "multiple" })%>

This displays the dropdown with the values that I'm passing in (Model.items) selected properly like what I'd expect:

<%= Html.DropDownList("somethingelse", new MultiSelectList(Model.AvailableItems,
    "id", "name", Model.items), new { multiple = "multiple" })%>

But the problem is that this item is now named "somethingelse" when i POST. I know I can hack around this but what's going?

+1  A: 

Too little context provided in your question but I will try to show a full working example:

Model:

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

public class MyModel
{
    public IEnumerable<int> SelectedItemIds { get; set; }
    public IEnumerable<Item> AvailableItems { 
        get 
        {
            return new[] 
            {
                new Item { Id = 1, Name = "Item 1" },
                new Item { Id = 2, Name = "Item 2" },
                new Item { Id = 3, Name = "Item 3" },
            };
        } 
    }
}

Controller:

[HandleError]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyModel
        {
            SelectedItemIds = new[] { 2, 3 }
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(IEnumerable<int> selectedItemIds)
    {
        var model = new MyModel
        {
            // Important: Don't ever try to modify the selectedItemIds here
            // The Html helper will completely ignore it and use 
            // the POSTed values
            SelectedItemIds = selectedItemIds
        };
        return View(model);
    }
}

View:

<% using (Html.BeginForm()) { %>
    <%= Html.ListBoxFor(x => x.SelectedItemIds, 
        new MultiSelectList(Model.AvailableItems, "Id", "Name")) %>
    <input type="submit" value="GO" />
<% } %>

Notice that the Html.ListBoxFor is more adapted if you want to generate a multiple select. Obviously the AvailableItems property should be fetched from a repository.

Darin Dimitrov
+1  A: 

Hey Andrew

The problem you have is using Model.Items as a parameter. The code

<%= Html.DropDownList("items", new MultiSelectList(Model.AvailableItems,
    "id", "name", Model.items), new { multiple = "multiple" })%>

isn't actually working as you would expect. It's working because the name of the dropdown is "items". That's because there was a form param called "items" posted back to your action. That param gets stored in the action's ViewState (don't confise with ViewData). The Html.DropdownList() sees that there is a ViewState param named the same as you have named your dropdown and uses that ViewState param to work out the selected values. It completely ignores the Model.items that you passed in.

If anyone can explain the logic of not being able to override the default behaviour then I'd love to hear it.

So, that's your first problem. To get around it all you have to do is to rename the dropdown to something else - exactly like you did in your second example. Now your second problem comes into play: the list of selected items must be a collection of simple objects (I think it actually needs to be an IEnumerable but I'm not 100% sure).

The DropdownList() method will try and match those selected values to the Value in your AvailableItems collection. If it can't do that it will try to match against the Text.

So, try this to see if it works

<%= Html.DropDownList("somethingelse", new MultiSelectList(Model.AvailableItems,
    "id", "name", Model.items.Select(c=> c.name)), new { multiple = "multiple" })%>

Good luck

Jero G