Index of current item in mvc display template

2019-06-19 02:57发布

问题:

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>

回答1:

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.



回答2:

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>


回答3:

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:

  1. First items in List
  2. 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;
}