iLemming
iLemming

Reputation: 36166

How can I easily create a DropDownList from within the controller

I have a partial view that contains a few <div>s that look the same and every each of them in their turn contain a DropdownList. Now, selected values in the DropdownLists usually different. And initial list of values comes from some external source. So that would't work:

public PartialViewResult GetMeals()
{
      var meals = DataContext.GetMeals();
      ViewBag.Units = new SelectList(DataContext.GetUnits,"Id","Name");

      return PartialView("_Meals", meals);
 }

@foreach (var m in Meals)
 {
     <div>  
         @Html.DropDownList("Units", ViewBag.Units as List<SelectListItem>)
     <dig>

I can of course create another partial view for each Meal, but I don't wanna get into a partial views hierarchy and create Partial inside another Partial (Although Leo DiCaprio would've love that)

Can you guys give me an advice?

Upvotes: 1

Views: 176

Answers (1)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038720

Here's what I would do. This first thing is to get rid of ViewBag. Then define a view model:

public class MealViewModel
{
    public string MealDescription { get; set; }

    public string SelectedUnit { get; set; }
    public IEnumerable<SelectListItem> Units { get; set; }
}

Inside this view model you put only what your view (partial view in this case) needs.

and then I would have my controller action populate this view model by aggregating data from wherever you want:

public ActionResult GetMeals()
{
    var meals = DataContext.GetMeals().ToList(); // <-- being eager with .ToList()
    var units = DataContext.GetUnits().ToList(); // <-- being eager with .ToList()
    var viewModel = meals.Select(meal => new MealViewModel
    {
        MealDescription = meal.Description,
        SelectedUnit = meal.UnitId,
        Units = units.Select(unit => new SelectListItem
        {
            Value = unit.Id.ToString(),
            Text = unit.Name
        })
    });
    return PartialView("_Meals", viewModel);
}

and inside the partial _Meals I would use editor templates:

@model IEnumerable<MealViewModel>
@Html.EditorForModel()

and finally I would define an editor template for a meal: (~/Views/Shared/EditorTemplates/MealViewModel.cshtml) which will be rendered for each element of the model:

@model MealViewModel
<h3>@Html.DisplayFor(x => x.MealDescription)</h3>
<div>    
    @Html.DropDownListFor(
        x => x.SelectedUnit,
        new SelectList(Model.Units)
    )
</div>

Now more loops, casts, wrongly named input controls. You get strongly typed, Intellisense enabled views, yummy :-)

Now when you look at the controller action there must be something that bothers you: this repetitive mapping code between your domain models and the view models. Enter the world of AutoMapper and you will get really pretty code.

Upvotes: 2

Related Questions