Razor loop item index
(fairly new to Razor). The following is very pseudo-modified and extracted from my code. Maybe I don't have the correct terminology or know exactly which parts are the main and custom code.)
I want to be able to access the order / index of each element in a for-loop element. (ie in item # 1 I can refer to "1", and in item # 2 I can refer to "2", etc.). So I can use it. SORT like this (I don't care how I get it, just which I get):
item.cshtml:
@model myWidgetViewModel
<a href="foo"
@TrackingHelper.SetInfo(new ClickTrackInfo {
item = @Model.Name,
index= @Model.idx
})
>
@Model.Name
</a>
wrapper.cshtml
@model myWidgetViewModel
@foreach (var item in Model.myWidgetItems)
{
@Html.Partial(item.View, item)
}
Conceptually, what I'm trying to do is:
@model myWidgetViewModel
@{int idx = 0;}
@foreach (var item in Model.myWidgetItems)
{
@Html.Partial(item.View, item, idx)
idx++;
}
But of course this doesn't work (@ Html.Partial only takes 2 arguments).
source to share
There are several ways to handle what you would like:
1: include a property in your partial view model :
You will need to change your partial view model regardless of the element type to have a new int type property named WidgetIndex, and then you can do this:
@model myWidgetViewModel
@{int idx = 0;}
@foreach (var item in Model.myWidgetItems)
{
item.WidgetIndex = idx;
@Html.Partial(item.View, item)
idx++;
}
... then, in partial, you can use it:
<div>@Model.WidgetIndex</div>
2: put it in your watch bag (note that you can call the property anything, not just WidgetIndex:
@model myWidgetViewModel
@{int idx = 0;}
@foreach (var item in Model.myWidgetItems)
{
ViewBag.WidgetIndex = idx;
@Html.Partial(item.View, item)
idx++;
}
... then, in partial, you can grab it:
<div>@ViewBag.WidgetIndex</div>
3: You can use ViewData:
@model myWidgetViewModel
@{int idx = 0;}
@foreach (var item in Model.myWidgetItems)
{
ViewData.Add("WidgetIndex", idx);
@Html.Partial(item.View, item)
idx++;
}
in partial:
<div>@ViewData["WidgetIndex"]</div>
suggestions
You can use the IndexOf method instead of storing the variable (note that I used the code from solution 1 as an example):
@foreach (var item in Model.myWidgetItems)
{
item.WidgetIndex = Model.myWidgetItems.IndexOf(item);
@Html.Partial(item.View, item)
idx++;
}
You can use RenderPartial instead of Partial for better performance:
@foreach (var item in Model.myWidgetItems)
{
item.WidgetIndex = Model.myWidgetItems.IndexOf(item);
@{Html.RenderPartial(item.View, item);}
idx++;
}
source to share
Send a tuple to a partial
var args = new Tuple<myWidgetItemType, int>(item, idx);
@Html.Partial(item.View, args)
And then take that as a model in a partial (note: you are using var in your foreach loop, so it is difficult to specify the type exactly myWidgetItemType
)
@model Tuple<myWidgetItemType,int>
In your exact scenario, it would look like this:
wrapper.cshtml
@model myWidgetViewModel
@{
int idx = 0;
}
@foreach (var item in Model.myWidgetItems)
{
var args = new Tuple<myWidgetItemType, int>(item, idx++);
@Html.Partial(item.View, args)
}
item.cshtml
@model Tuple<myWidgetItemType,int>
<a href="foo"
@TrackingHelper.SetInfo(new ClickTrackInfo {
item = @Model.Item1.Name,
index= @Model.Item2
})
>
@Model.Item1.Name
</a>
source to share