8

Is there any way to say my view model property should be rendered as DropDownList (so that I can specify DropDownList items)?

I have found a lot of custom implementations but I guess there should be a built-in way to implement such a basic thing.

Update. I am rendering my model by Html.EditorForModel method, I don't want to use methods like Html.DropDownListFor

Mrchief
  • 75,126
  • 20
  • 142
  • 189
SiberianGuy
  • 24,674
  • 56
  • 152
  • 266

2 Answers2

14

There's no built-in template which renders a dropdown list, except for the Nullable<bool> type which renders a Not Set, Yes, No dropdown but I assume that's not what you are asking about.

So let's build one. As always we start by defining the view model that will represent a dropdown containing 2 properties (one for the selected value and one for the available values):

public class ItemViewModel
{
    public string SelectedId { get; set; }
    public IEnumerable<SelectListItem> Items { get; set; }
}

then we could have a standard view model with this property:

public class MyViewModel
{
    public ItemViewModel Item { get; set; }
}

then a controller that will fill the view model:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel
        {
            Item = new ItemViewModel
            {
                SelectedId = "2",
                Items = new[]
                {
                    new SelectListItem { Value = "1", Text = "item 1" },
                    new SelectListItem { Value = "2", Text = "item 2" },
                    new SelectListItem { Value = "3", Text = "item 3" },
                }
            }
        };
        return View(model);
    }
}

and a corresponding view (~/Views/Home/Index.cshtml):

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.EditorForModel()
}

Now all that's left is to define a custom editor template for the DropDownViewModel type (~/Views/Shared/EditorTemplates/DropDownViewModel.cshtml):

@model DropDownViewModel
@Html.DropDownListFor(
    x => x.SelectedId, 
    new SelectList(Model.Items, "Value", "Text", Model.SelectedId)
)

and override the default template for the Object type in order to allow Deep Dive as Brad Wilson explains in his blog post. Otherwise by default ASP.NET MVC won't recurse into complex subtypes for your templates. So we override ~/Views/Shared/EditorTemplates/Object.cshtml:

@foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForEdit && !ViewData.TemplateInfo.Visited(pm))) 
{
    if (prop.HideSurroundingHtml) 
    {
        @Html.Editor(prop.PropertyName)
    } 
    else 
    { 
        <div class="editor-label">
            @(prop.IsRequired ? "*" : "")
            @Html.Label(prop.PropertyName)
        </div>
        <div class="editor-field">
            @Html.Editor(prop.PropertyName)
            @Html.ValidationMessage(prop.PropertyName, "*")
        </div>
    }
}
Matthew Dresser
  • 11,273
  • 11
  • 76
  • 120
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    what is DropDownViewModel in the controller, is it ItemViewModel ? – mmssaann Jul 16 '13 at 05:12
  • This is not displaying dropdown for me. it is playing is item in text boxes.May be I am doing something wrong in controller with DropDownViewModel. I cannot find this class here. can u pls advise? – mmssaann Jul 16 '13 at 05:18
  • 1
    Got it, It is naming issue. I must give same name that is "ItemViewModel" for the editortemplate file also. – mmssaann Jul 16 '13 at 05:20
  • Some reason to use `IEnnumerable` in ViewModel instead of `List` for example ? – Muflix May 16 '17 at 17:28
1

You could use Html Helper DropDownList to build your drop down list but the model object should be inumerable of SelectionListItem.

//on controller
    List<SelectListItem> items = new List<SelectListItem>();
     items.Add(new SelectListItem { Text = "Action", Value = "0"});
     items.Add(new SelectListItem { Text = "Drama", Value = "1" });
     items.Add(new SelectListItem { Text = "Comedy", Value = "2", Selected = true });
     items.Add(new SelectListItem { Text = "Science Fiction", Value = "3" });
     ViewBag.MovieType = items;

//on view

         @Html.DropDownList("MovieType")

If you do not want to build your Model object as SelectListItem, then you should use DropDownListFor

//you can use DropDownListFor as
 @Html.DropDownListFor(m=>m.Text,m.Value)
Anand
  • 14,545
  • 8
  • 32
  • 44