I have a model that has the IEnumerable property (warning pseudocode)
public class PersonModel { public string Name { get; set; } public IEnumerable<AddressModel> Addresses { get; set; } } public class AddressModel { public string Name { get; set; } }
I want to display Address sub-objects in the same view
Person.cshtml
@model PersonModel <form> <h2>Person</h2> @Html.EditorFor(m=>m.Name) <ul>@Html.EditorFor(m=>m.Addresses)</ul> </form>
EditorTemplate / AddressModel
@model AddressModel <li>@Html.TextboxFor(m=>m.Name)</li>
Great, everything works great
But, being git, now I want to start using template templates to wrap all my properties with a standard type, etc.
So, I create string.cshtml and list.cshtml for this, using _Control.cshtml for the layout
EditorTemplates / _Control.cshtml
<div> @Html.Label(string.Empty) <div class="input"> @RenderBody() @Html.ValidationMessage(string.Empty) </div> </div>
EditorTemplates / string.cshtml
@model string @{ Layout = "_Control.cshtml"; } @Html.TextBox(string.Empty, Model)
(still yay !, but wait .. oh no ..)
Here is the problem
<ul>@Html.EditorFor(m=>m.Addresses)</ul>
from the main view (see above) becomes
@Html.EditorFor(m=>m.Addresses, "List")
EditorTemplates / list.cshtml
@model IEnumerable<object> @{ Layout = "_Control.cshtml"; } <ul> @foreach(var item in Model){ @Html.EditorFor(m => item) } </ul>
This incorrectly displays the identifier and names, for example Addresses_item_Name, which does not contain the identifier, so adding an identifier with a for loop
@for (var i = 0; i < Model.Count();i++ ) { @Html.EditorFor(m => Model.ElementAt(i)) }
This explodes because the MVC expression helper allows nothing but arrays, but Addresses must be IEnumerable <> because EF4.1 does not support .ToArray inside a subquery, i.e.
var model = (from p in DataContext.People where p.Id = 1 select new PersonModel { Name = p.Name, Addresses = (from a in p.Addresses select new AddressModel { Name = a.Name }).ToArray()
Has anyone come up with this? Is there a standard way to do this?
It works, but right?
EditorTemplates / list.cshtml
@model IEnumerable<object> @{ Layout = "_Control.cshtml"; var prefix = ViewData.TemplateInfo.HtmlFieldPrefix; } <ul> @for (var i = 0; i < Model.Count();i++ ) { var item = Model.ElementAt(i); ViewData.TemplateInfo.HtmlFieldPrefix = string.Format("{0}[{1}]",prefix, i); @Html.EditorFor(m => item, null, string.Empty) } </ul>
Required structure
<form> <control> Person Name Control Elements <control> <control> Address List Control Elements <control> </form>