Reputation: 36166
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
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