Getting index value on razor foreach

asp.net Mvcasp.net Mvc-2RazorPartial Views

asp.net Mvc Problem Overview


I'm iterating a List<T> in a razor foreach loop in my view which renders a partial. In the partial I'm rendering a single record for which I want to have 4 in a row in my view. I have a css class for the two end columns so need to determine in the partial whether the call is the 1st or the 4th record. What is the best way of identifying this in my partial to output the correct code?

This is my main page which contains the loop:

@foreach (var myItem in Model.Members){

        //if i = 1
        <div class="grid_20">
        <!-- Start Row -->

        //is there someway to get in for i = 1 to 4 and pass to partial?
        @Html.Partial("nameOfPartial", Model)

        //if i = 4 then output below and reset i to 1
        <div class="clear"></div>
        <!-- End Row -->
        </div>

}

I figure I can create a int that I can update on each pass and render the text no problem here but it's passing the integer value into my partial I'm more concerned about. Unless there's a better way.

Here is my partial:

@{
switch()
case 1:
        <text>
        <div class="grid_4 alpha">
        </text>
break;
case 4:
        <text>
        <div class="grid_4 omega">
        </text>
break;
default:
        <text>
        <div class="grid_4">
        </text>
break;
}

        <img src="Content/960-grid/spacer.gif" style="width:130px; height:160px; background-color:#fff; border:10px solid #d3d3d3;" />
        <p><a href="member-card.html">@Model.Name</a><br/>
        @Model.Job<br/>
        @Model.Location</p>
</div>

Not sure if I'm having a blonde day today and this is frightfully easy but I just can't think of the best way to pass the int value in. Hope someone can help.

asp.net Mvc Solutions


Solution 1 - asp.net Mvc

 @{int i = 0;}
 @foreach(var myItem in Model.Members)
 {
     <span>@i</span>
     @{i++;
      }
 }

// Use @{i++ to increment value}

Solution 2 - asp.net Mvc

//this gets you both the item (myItem.value) and its index (myItem.i)
@foreach (var myItem in Model.Members.Select((value,i) => new {i, value}))
{
    <li>The index is @myItem.i and a value is @myItem.value.Name</li>
}

More info on my blog post http://jimfrenette.com/2012/11/razor-foreach-loop-with-index/

Solution 3 - asp.net Mvc

Or you could simply do this:

@foreach(var myItem in Model.Members)
{    
    <span>@Model.Members.IndexOf(myItem)</span>
}

Solution 4 - asp.net Mvc

Take a look at this solution using Linq. His example is similar in that he needed different markup for every 3rd item.

foreach( var myItem in Model.Members.Select(x,i) => new {Member = x, Index = i){
    ...
}

Solution 5 - asp.net Mvc

You could also use deconstruction and tuples and try something like this:

@foreach (var (index, member) in @Model.Members.Select((member, i) => (i, member)))
{
  <div>@index - @member.anyProperty</div>

  if(index > 0 && index % 4 == 0) { // display clear div every 4 elements
      @: <div class="clear"></div>
  }
}

For more info you can have a look at this link

Solution 6 - asp.net Mvc

Is there a reason you're not using CSS selectors to style the first and last elements instead of trying to attach a custom class to them? Instead of styling based on alpha or omega, use first-child and last-child.

http://www.quirksmode.org/css/firstchild.html

Solution 7 - asp.net Mvc

IndexOf seems to be useful here.

@foreach (myItemClass ts in Model.ItemList.Where(x => x.Type == "something"))
    {
       int currentIndex = Model.ItemList.IndexOf(ts);
       @Html.HiddenFor(x=>Model.ItemList[currentIndex].Type)

...

Solution 8 - asp.net Mvc

Very Simple:

     @{
         int i = 0;
         foreach (var item in Model)
         {
          <tr>
          <td>@(i = i + 1)</td>`
          </tr>
         }
      }`

Solution 9 - asp.net Mvc

All of the above answers require logic in the view. Views should be dumb and contain as little logic as possible. Why not create properties in your view model that correspond to position in the list eg:

public int Position {get; set}

In your view model builder you set the position 1 through 4.

BUT .. there is even a cleaner way. Why not make the CSS class a property of your view model? So instead of the switch statement in your partial, you would just do this:

<div class="@Model.GridCSS">

Move the switch statement to your view model builder and populate the CSS class there.

Solution 10 - asp.net Mvc

In case you want to count the references from your model( ie: Client has Address as reference so you wanna count how many address would exists for a client) in a foreach loop at your view such as:

 @foreach (var item in Model)
                        {
                            <tr>
                                <td>
                                    @Html.DisplayFor(modelItem => item.DtCadastro)
                                </td>

                                <td style="width:50%">
                                    @Html.DisplayFor(modelItem => item.DsLembrete)
                                </td>
                                <td>
                                    @Html.DisplayFor(modelItem => item.DtLembrete)
                                </td>
                                <td>
                                    @{ 
                                        var contador = item.LembreteEnvolvido.Where(w => w.IdLembrete == item.IdLembrete).Count();
                                    }
                                    <button class="btn-link associado" data-id="@item.IdLembrete" data-path="/LembreteEnvolvido/Index/@item.IdLembrete"><i class="fas fa-search"></i> @contador</button>
                                    <button class="btn-link associar" data-id="@item.IdLembrete" data-path="/LembreteEnvolvido/Create/@item.IdLembrete"><i class="fas fa-plus"></i></button>
                                </td>
                                <td class="text-right">
                                    <button class="btn-link delete" data-id="@item.IdLembrete" data-path="/Lembretes/Delete/@item.IdLembrete">Excluir</button>
                                </td>
                            </tr>
                        }

do as coded:

@{ var contador = item.LembreteEnvolvido.Where(w => w.IdLembrete == item.IdLembrete).Count();}

and use it like this:

<button class="btn-link associado" data-id="@item.IdLembrete" data-path="/LembreteEnvolvido/Index/@item.IdLembrete"><i class="fas fa-search"></i> @contador</button>

ps: don't forget to add INCLUDE to that reference at you DbContext inside, for example, your Index action controller, in case this is an IEnumerable model.

Solution 11 - asp.net Mvc

I prefer to use this extension method:

public static class Extensions
{
    public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self)
        => self.Select((item, index) => (item, index));
}

Source:

https://stackoverflow.com/a/39997157/3850405

Razor:

@using Project.Shared.Helpers 

@foreach (var (item, index) in collection.WithIndex())
{
<p>
    Name: @item.Name Index: @index
</p>
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionlloydphillipsView Question on Stackoverflow
Solution 1 - asp.net MvcnoamtcohenView Answer on Stackoverflow
Solution 2 - asp.net MvcJim FrenetteView Answer on Stackoverflow
Solution 3 - asp.net MvcManoj De MelView Answer on Stackoverflow
Solution 4 - asp.net MvcbrightgardenView Answer on Stackoverflow
Solution 5 - asp.net MvcppolyzosView Answer on Stackoverflow
Solution 6 - asp.net MvcTimothy StrimpleView Answer on Stackoverflow
Solution 7 - asp.net MvcRichCView Answer on Stackoverflow
Solution 8 - asp.net Mvcpeeyush singhView Answer on Stackoverflow
Solution 9 - asp.net MvcLouise EggletonView Answer on Stackoverflow
Solution 10 - asp.net MvcJust FairView Answer on Stackoverflow
Solution 11 - asp.net MvcOgglasView Answer on Stackoverflow