I have an mvc page with a displaytemplate.
How do I get the index of the current item being rendered in the displaytemplate.
it produces correct bindable results in the name attributes.
<input name="xxx[0].FirstName"/>
<input name="xxx[1].FirstName"/>
I want that index value in the display template. Is it in the ViewContext somewhere?
@* page.cshtml @
@model ...@ property Contacts is IEnumerable *@
<table id="contacts" class="editable">
<thead>
<tr><th>Name</th><th>Surname</th><th>Contact Details</th></tr>
</thead>
<tbody>
@Html.DisplayFor(x => x.Contacts)
</tbody>
in the display template we have
@* contact.cshtml *@
@model ...@* This is the T of the IEnumerable<T> *@
<tr>
@* I NEED THE INDEX OF THE CURRENT ITERATION HERE *@
<td>@Html.DisplayFor(x => x.FirstName)</td>
</tr>
I am afraid there is no easy way to get the index. It's buried inside the internal System.Web.Mvc.Html.DefaultDisplayTemplates.CollectionTemplate
method and not exposed. What you could use is the field prefix:
@ViewData.TemplateInfo.HtmlFieldPrefix
Another possibility is replace @Html.DisplayFor(x => x.Contacts)
with:
@for (int i = 0; i < Model.Contacts.Length; i++)
{
@Html.DisplayFor(x => x.Contacts[i], new { Index = i })
}
and then inside the template @ViewBag.Index
should give you the current index but I must admit it's kinda ugly.
Extending @DarinDimitrov's answer, I wanted to submit a complete solution:
Extention:
namespace ApplicationName.Helpers
{
public static class RazorHtmlHelpers
{
public static Int32 GetTemplateIndex(this TemplateInfo template)
{
var index = 0;
var match = Regex.Match(template.HtmlFieldPrefix, @"\d");
Int32.TryParse(match.Value, out index);
return index;
}
}
}
Parent View Markup:
@Html.DisplayFor(model => model.Items)
Template Markup:
@using ApplicationName.Helpers
@model ApplicationName.Models.ModelName
<span>Item @ViewData.TemplateInfo.GetTemplateIndex()</span>
Depending on why you need the index, there may be an easier way.
I was doing something similar and wanted the index just so I could easily number the list of items such as:
- First items in List
- Second item in List
etc.
The maybe obvious solution was to render my display template as a List Item within an Order List, and let the browser handle the display of the index. I was originally doing this in a table and needed the index to display in the table, but using a ordered list makes it much easier.
So my parent view had the following:
<ol>
@Html.DisplayFor(m => m.Items)
</ol>
And my template wrote on the items in an list item using divs - note you could use floating divs, or better yet display: inline-style to get a table like effect
<li>
<div class="class1">@Html.DisplayFor(m => m.ItemType)</div>
...
</li>
And the css:
.class1 {
display: inline-block;
width: 150px;
}