Search code examples
c#asp.net-mvcrazorasp.net-coreasp.net-core-mvc

Bind a Razor select to a Dictionary from ViewData


I'm writing a web-app with .NET Core MVC (dotnet version 1.0.4).

I want to pass a Dictionary<string, string> in a ViewData object from controller to view and bind it to <select> element.

This is a result that I want to get:

enter image description here

And I tried two ways to achieve it.

1st way

Controller's code

Dictionary<string, string> animals = new Dictionary<string, string>();
animals.Add("1", "cat");
animals.Add("2", "dog");
animals.Add("3", "bunny");

ViewData["animals"] = new SelectList(animals);

Views's code

<select asp-for="Animal_id" asp-items="(SelectList)@ViewData["animals"]" class="form-control"></select>

That gives me this result

enter image description here

2nd way

Controller's code

Dictionary<string, string> animals = new Dictionary<string, string>();
animals.Add("1", "cat");
animals.Add("2", "dog");
animals.Add("3", "bunny");

ViewData["animals"] = new SelectList(animals.Select(r => new SelectListItem
{
    Text = r.Key,
    Value = r.Value
}));

Views's code

The same.

That gives me this result:

enter image description here

Apparently, something I don't understand about this concept, although I feel like I'm on a right track. Can you please help me - what needs to be done in order to get the result from my first picture (<option>s with values)?


Solution

  • You using the overload of the SelectList constructor where the parameter is IEnumerable. That overload calls the .ToString() method of each item in your collection, and because they are complex objects, you get the results your seeing. That overload is really only useful if your collection was IEnumerable<string>.

    You need to use the overload that accepts arguments for the dataValueField and dataTextField which defines the properties to be used for the options value and display text.

    Dictionary<string, string> animals = new Dictionary<string, string>();
    animals.Add("1", "cat");
    animals.Add("2", "dog");
    animals.Add("3", "bunny");
    
    ViewData["animals"] = new SelectList(animals, "Key", "Value");
    

    Note also in your 2nd example, you have already generated an IEnumerable<SelectListItem> To use new SelectList(...) to create an identical IEnumerable<SelectListItem> from the first one is pointless extra ovehead and it can just be

    ViewData["animals"] = animals.Select(r => new SelectListItem
    {
        Text = r.Key,
        Value = r.Value
    }));
    

    and in the view asp-items="(IEnumerable<SelectListItem>)@ViewData["animals"]"