I have a nested class such as :
public class Jar
{
public IEnumerable<NailClippings> Nails { set; get; }
public IEnumerable<People> Donors { set; get; }
}
My controller passes a single Jar
to my view, string typed as
@model Test.ViewModels.Jar
I can loop through the contents of Nails
and Donors
easily with something like this
@foreach(var item in Model.Nails)
My issue is with using HTML helpers to generate Display names for me
@Html.DisplayNameFor(model => model.Nails.Length)
I have come up with a solution by changing the type of the inner nested classes to List
, appending .ToList()
at the end of my queries and changing the line to
@Html.DisplayNameFor(model => model.Nails[0].Length)
Being forced to use List
and have an index [0]
to display a name is goofy to me. Is there an alternative method for referencing inner nested class attributes?
Edit: View
<table>
<tr>
<th>@Html.DisplayNameFor(model => model.Nails[0].Length)</th>
.
.
</tr>
@foreach(var item in Model.Nails){
<tr>
<td>@Html.DisplayFor(modelItem => item.Length</td>
.
.
</tr>
}
</table>
You don't need to be writing any loops in your views. It makes them so ugly.
Simply define a corresponding display template for the collection type. So for example you would create
~/Views/Shared/DisplayTemplates/NailClippings.cshtml
partial view that will be strongly typed to a single element of the collection:and now inside your main view it's as simple as:
Display/editor templates work by convention. So here when inside your main view you use
@Html.DisplayFor(x => x.Nails)
, ASP.NET MVC will analyze the type of theNails
property and will see that it is anIEnumerable<NailClippings>
collection. So it will start looking for a corresponding display template first inside~/Views/CurrentController/DisplayTemplates/NailClippings.cshtml
, then inside~/Views/Shared/DisplayTemplates/NailClippings.cshtml
and finally it will fallback to thedefault display template
. When a template is selected this template will automatically be executed for you by ASP.NET MVC for each element of the collection property so that you never have to worry about things like writing some loops in your views, worry about indexes, ...This also works with editor templates:
@Html.EditorFor(x => x.Nails)
will look for~/Views/Shared/EditorTemplates/NailClippings.cshtml
. The bonus you get here is that the generated input fields will have correct names and you when you submit the form, the default model binder will automatically rehydrate your view model that the HttpPost action is taking as argument from the request.Basically if you respect the conventions that the framework is following you will make your life much easier.
I think this sample code is useful for nested model class
Instead of
You could use
Without having to convert to a
List
.I think you can just use
item
variable of loopUPDATE another option for you is creating partial view for Nails displaying. It will be strongly typed to
IEnumerable<NailClippings>
and all properties will be available:Nails partial view: