I have an IEnumerable of a base type as my model.
I need to display a different bit of HTML in a list depending on what the concrete type is.
So the resulting list might look similar to this in HTML:
<ul>
<li class="points">Points - Item 1 - 10 points <a href="#">Remove</a></li>
<li class="media">Media - Item 2 - your_uploaded_image.jpg <a href="#">Remove</a></li>
<li class="content">Content - Item 3 <a href="#">Remove</a></li>
</ul>
It’s likely I will add another type to this later so solutions like the following aren’t really what I’m after.
@foreach(var item in Model)
{
if(item is PointImpl)
{
var pointItem = item as PointImpl;
<li class="points">Points - @pointItem.Name - @pointItem.Points points <a href="#">Remove</a></li>
}
else if(item is MediaImpl)
{
var mediaItem = item as MediaImpl;
<li class="media">Media - @mediaItem.Name - @mediaItem.FileName <a href="#">Remove</a></li>
}
/*
More implementations
*/
}
I’ve had a look at model metadata template hint but that doesn’t really help because my model is an IEnumerable..
I was thinking about a custom Html Helper looking at an attribute on the concrete type but think there might be a built in way of doing this?
Instead of the ugly
foreachsimply use display templates:and then define display templates for all child types. For example:
~/Views/Shared/DisplayTemplates/PointImpl.cshtml:and:
~/Views/Shared/DisplayTemplates/MediaImpl.cshtml:See, no more ifs, no more loops, no more vars. Everything works by convention (templates must be situated in the
~/Views/Shared/DisplayTemplatesor~/Views/SomeController/DisplayTemplatesfolder and should be named as the name of the concrete type –PointImpl.cshtml,MediaImpl.cshtml, …). Based on the concrete type the corresponding display template will be rendered and this automatically for each element of the main model collection.