How to add static list of items in MVC Html.DropDownList()

48,320

Solution 1

OK I decided to take my own advice, and this should be defined in the controller:

FYI, I just returned:

PageData data = new PageData()
           {
               Formats = new[]
                             {
                                 new { ID = "string", Name = "Text" },
                                 new { ID = "int", Name = "Numeric" },
                                 new { ID = "decimal", Name = "Decimal" },
                                 new { ID = "datetime", Name = "Date/Time" },
                                 new { ID = "timespan", Name = "Stopwatch" }
                             },
               .............

           };
return View(data);

... (ignore context) and in the View ASPX side:

<%= Html.DropDownList("type.field", new SelectList(ViewData.Model.Formats, "ID", "Name"...

If anyone has a more optimal way of doing this I'll be happy to accept their answer.

Solution 2

All MVC noobs initially avoid the 'M' word, but it does kinda start at the beginning of the MVC acronym. So maybe, just maybe, you might want to start your solution with a Model... just saying.

Do not Repeat Yourself (DRY). You're going to end up copying and pasting the "new PageData()" to each and every Controller that passes the option list to a View. Then you're going to want to delete or add an option and have to edit every controller's PageData.

Moreover, you want to type the least amount of code with the fewest unnecessarily verbose "add"s, "new"s, "IS"s, and "Name"s. Because you only have a key-value pair in the select option (and/or a radio button list), use the lightest data structure possible, i.e. a Dictionary --in your Model.

Then simply reference the Model in the Controller and convert the Dictionary to a SelectList in the View using a DropDownListFor containing a LINQ Lambda expression.

Intimidated? You're not alone. I certainly was. Here's an example I used to teach myself the M, the V, and the C:

The Model part of MVC:

using System.Web.Security;
using System.Collections.Generic;
using System.Text;
using System.Linq.Expressions;
using System.Web.Routing;
using System.Web.Helpers;
using System.Web.Mvc.Html;
using MvcHtmlHelpers;
using System.Linq;

// EzPL8.com is the company I work for, hence the namespace root. 
    // EzPL8 increases the brainwidths of waiters and bartenders by augmenting their "memories" with the identifies of customers by name and their food and drink preferences.
   // This is pedagogical example of generating a select option display for a customer's egg preference.  

namespace EzPL8.Models     
{
    public class MyEggs    
    {
        public Dictionary<int, string> Egg { get; set; }

        public MyEggs()  //constructor
        {
            Egg = new Dictionary<int, string>()
            {
                { 0, "No Preference"},  //show the complete egg menu to customers
                { 1, "I hate eggs"},    //Either offer an alternative to eggs or don't show eggs on a customer's personalized dynamically generated menu

                //confirm with the customer if they want their eggs cooked their usual preferred way, i.e.
                { 2, "Over Easy"},  
                { 3, "Sunny Side Up"},
                { 4, "Scrambled"},
                { 5, "Hard Boiled"},
                { 6, "Eggs Benedict"}
            };
    }
}

The Controller is now fairly simple, just passing the model. It avoids creating an isolated concept, which probably isn't isolated to just one page.:

public ActionResult Index()
{
   var model = new EzPL8.Models.MyEggs();
   return View(model);
}

The View uses DropDownListFor (instead of DropDownList) and a Lambda expression for strong typing in the event refactoring is required:

@Html.DropDownListFor(m => m.Egg, new SelectList( Model.Egg, "Key", "Value"))

Voilà, the resulting HTML:

<select id="Egg" name="Egg">
<option value="0">No Preference</option>
<option value="1">I hate eggs</option>
<option value="2">Over Easy</option>
<option value="3">Sunny Side Up</option>
<option value="4">Scrambled</option>
<option value="5">Hard Boiled</option>
<option value="6">Eggs Benedict</option>
</select>

Note: don't get confused by the VALUE in <option value="6">, which is the Key from the dictionary, from the "Value" in the SelectList(), which is the text/title (e.g. Eggs Benedict) that ends up between the option tags.

Use Case: To minimize traffic between the application and the database I created a static list to avoid a database query for the drop down list that rarely, if ever changes. However, change is inevitable and six-months from now a diner at my customer's restaurant dies; not because of the green ham, but because they were allergic to eggs and the cook mixed some in with their waffles.

The restaurant needs their customer info updated to include food allergies immediately. While they love repeat customers, they're not cool with dead customers coming back as zombies that have no way to pay because their credit cards were cancelled.

Rhetorical Question: Should I modify all the controllers and views related to customer egg preferences? Or simply insert { 7, "Allergic to Eggs"} into the model?

Another Rhetorical Question: Aren't omelettes eggs? Do you want to add {8, "Omelette, Western"}, {9, "Omelette, Mushroom-Feta-Spinach"} once to the model and have the new additions automagically propagate throughout all dropdown lists in all the views that use them?

Bottom line(s) This is probably way more than you asked for, ...but you did say MVC, not just VC:
1. Use a Model in *M*VC. 2. Use a dictionary in the Model when a select list is based on nothing more than a "primary key" and a title. 3. If your static list doesn't jive with a database Lookup table somewhere, your app probably isn't very useful. When you add an option to a static list, more than likely you'll also need to perform an insert to the Lookup table to avoid a primary key/foreign key relationship integrity error with other tables in the database. 4. Use lambda and strongly typed data structures to avoid errors and get typeahead support.

Share:
48,320
GONeale
Author by

GONeale

Full time thinker. Overtime coder. Part time real world. Follow me on Twitter

Updated on April 07, 2020

Comments

  • GONeale
    GONeale about 4 years

    I would like to assign a static list of items in a SelectList() to a Html.DropDownList() in ASP.NET MVC, what is the best practice?

    I was about to try to find a way to use new SelectList(new {key = "value"}... but one, that didn't work, and two, would I be breaking a law here, should my static list be declared in ViewData anyway and passed as IList/IENumerable?

  • GONeale
    GONeale about 15 years
    I have selected my answer as it is the one I went with.
  • Simon Martin
    Simon Martin about 11 years
    What's with all the EzPL8 references? I'm lost... or am I missing the joke?
  • Rich C
    Rich C about 11 years
    -1 for the EzPL8 story. +1 for pulling the data out of the Model.
  • Sakthivel
    Sakthivel almost 11 years
    This works fine, but if i want dropdown to load Decimal as a startup value, what should i do ?
  • Louise Eggleton
    Louise Eggleton about 5 years
    Defining it in the controller is better than the view, but it should really be in the model as @JulesBartow suggests. What if you want to reuse the drop-down elsewhere? Cut and paste is not the right answer.