JK.
JK.

Reputation: 21826

C# MVC3 Razor alternating items in a @foreach list?

In MVC3, how do you create alternating row colors on a @foreach list when using the Razor view engine?

@foreach (var item in Model) {    
    <tr>
        <td>@item.DisplayName</td>
        <td>@item.Currency</td>
        <td>@String.Format("{0:dd/MM/yyyy}", item.CreatedOn)</td>
        <td>@String.Format("{0:g}", item.CreatedBy)</td>
        <td>@Html.ActionLink("Edit", "Edit", new { id = item.Id })</td>
    </tr>
}

Upvotes: 46

Views: 99611

Answers (14)

Tim
Tim

Reputation: 85

An old post, but none of the answers covered this approach, so I will.

Since you are using MVC Razor utilizing the @helper function is the simplest, cleanest and best approach.

In the App_Code folder of your project add new item or modify your existing CustomeHelpers.cshtml file with the following code:

@helper AlternateBackground(string color, Int32 iViewBagCount) {
    if (iViewBagCount == null) { iViewBagCount = 0; }
    <text>style="background-color:@(iViewBagCount % 2 == 1 ? color : "none")"</text>
    iViewBagCount++;
}

Then on your view your foreach loop would look like this:

@foreach (var item in Model) {    
    <tr @CustomHelpers.AlternateBackground("#ECEDEE", Model.Count())>
        <td>@item.DisplayName</td>
        <td>@item.Currency</td>
        <td>@String.Format("{0:dd/MM/yyyy}", item.CreatedOn)</td>
        <td>@String.Format("{0:g}", item.CreatedBy)</td>
        <td>@Html.ActionLink("Edit", "Edit", new { id = item.Id })</td>
    </tr>
}

You can pass a color identifier like "#ECEDEE" or the named color "Blue".

This way you only have to add the @Helper function once and it propagates throughout your application and it can be called on each view as needed by referencing the @CustomHelpers function.

Upvotes: 1

user1724001
user1724001

Reputation: 119

@helper Prop(List prop) { foreach (var p in prop) { p } }

format: @Prop(@item.Prop)

Upvotes: 0

Tom Lindelius
Tom Lindelius

Reputation: 11

What you can do is to set a variable odd outside of the foreach()

@{
    var odd = false;
}

And then, inside your foreach loop, you'd change the value of it and then use it in an if condition to set the alternating classes.

@foreach (var item in Model) {
    odd = !odd;

    <tr class="@(odd ? "odd" : "even")">
        <td>@item.DisplayName</td>
        <td>@item.Currency</td>
        <td>@String.Format("{0:dd/MM/yyyy}", item.CreatedOn)</td>
        <td>@String.Format("{0:g}", item.CreatedBy)</td>
        <td>@Html.ActionLink("Edit", "Edit", new { id = item.Id })</td>
    </tr>
}

Upvotes: 1

Craig Tullis
Craig Tullis

Reputation: 10507

You could let the framework decide how best to render it, presumably using a bit of browser detection logic and whatever other goodness it has built-in, something like the following, and get on with your life.

:-)

My point being that with this approach the WebGrid will control the alternating grid colors using the best technology it can (best that it is designed to use, at least) for the detected browser. It might not use "nth" CSS syntax, but that might not work for all of your intended audience, anyway, so you'd have to detect the browser and emit different content on your own. Of course everybody should be using a CSS 3.x-compliant browser by now, but mileage varies.

@myWebGrid.GetHtml
    (
    tableStyle: "some-style",
    headerStyle: "some-head-style",
    alternatingRowStyle: "some-fancy-alt-row-style",
    etc ...
    )

The System.Web.Helpers.WebGrid's GetHtml method signature looks like this here:

public IHtmlString GetHtml
    (
    string tableStyle = null,
    string headerStyle = null,
    string footerStyle = null,
    string rowStyle = null,
    string alternatingRowStyle = null,
    string selectedRowStyle = null,
    string caption = null,
    bool displayHeader = true,
    bool fillEmptyRows = false,
    string emptyRowCellValue = null,
    IEnumerable<WebGridColumn> columns = null,
    IEnumerable<string> exclusions = null,
    WebGridPagerModes mode = WebGridPagerModes.Numeric | WebGridPagerModes.NextPrevious,
    string firstText = null,
    string previousText = null,
    string nextText = null,
    string lastText = null,
    int numericLinksCount = 5,
    object htmlAttributes = null
    );

Upvotes: 0

Jake1164
Jake1164

Reputation: 12369

A solution i use to support IE8 (corporate browser, not by choice) was to combine the_lotus's solution with a jquery solution

Since IE8 doesnt support nth-child() use this css

.tableclass tr.even{
    background:#E6EDF5;
}

And use jQuery to do this:

$(document).ready(function() {
    $(".table tr:nth-child(even)").addClass("even");
});

Upvotes: 0

Ken Pespisa
Ken Pespisa

Reputation: 22264

With ASP.NET MVC 3 and the new @helper syntax, there is a neater way to handle this.

First add this @helper method:

@helper AlternateBackground(string color) {
    if (ViewBag.count == null) { ViewBag.count = 0; }
    <text>style="background-color:@(ViewBag.count % 2 == 1 ? color : "none")"</text>
    ViewBag.count++;
}

Then just add the call to the helper in your <TR> element

@foreach (var item in Model) {    
    <tr @AlternateBackground("Red")>
        <td>@item.DisplayName</td>
        <td>@item.Currency</td>
        <td>@String.Format("{0:dd/MM/yyyy}", item.CreatedOn)</td>
        <td>@String.Format("{0:g}", item.CreatedBy)</td>
        <td>@Html.ActionLink("Edit", "Edit", new { id = item.Id })</td>
    </tr>
}

Upvotes: 25

the_lotus
the_lotus

Reputation: 12748

You could always do it in pure css using:

TABLE.test tr:nth-child(even)
{
    background-color: #EFEFEF;
}

Upvotes: 22

MondayPaper
MondayPaper

Reputation: 1579

@{  
    int i = 0;
    foreach (Account acct in Model)
    {
        <div class="row @(i%2==0?"even":"odd")">     
            <a href="/Account/Details/@acct.id">@acct.name</a>
        </div>
        i++;
    }
}

Upvotes: 5

Thant Zin
Thant Zin

Reputation: 543

Original: http://15daysofjquery.com/table-striping-made-easy/5/ Author: Jack Born jQuery Zebra_Striping_Made_Easy

=============== Java script ===================

$(document).ready(function () {
          $('.stripeMe tr:even').addClass('alt');

          $('.stripeMe tr').hover(
            function () {
                $(this).addClass("highlight");
              },
             function () {
                $(this).removeClass("highlight");
              });
      });

================= css =================

tr.alt td {
background-color : #F7F7F7;
}
tr.highlight td {
background-color : #bcd4ec;
}

=============== HTML ===============

<table class="stripeMe">

Upvotes: 3

trebormf
trebormf

Reputation: 3224

This is what CSS is for (changing style rather than content). Save the server the effort: Do it on the client.

Since you're using Razor, you can use JQuery. Here's how I do it in my projects:

$(document).ready(function () {
    $("table > tbody tr:odd").css("background-color", "#F7F7F7");
}

Upvotes: 42

Anthony
Anthony

Reputation: 536

what about using the jQuery DataTable plugin. i used it on an MVC2 application i developed.

http://www.datatables.net/

Upvotes: 0

Andrew Stanton-Nurse
Andrew Stanton-Nurse

Reputation: 6294

There isn't much documentation on it, but the Loop Helper (http://nuget.org/Packages/Packages/Details/Loop-Helper-for-WebMatrix-0-1) gives you support for detecting Even/Odd/etc. items.

Upvotes: 2

Kirk Woll
Kirk Woll

Reputation: 77586

Assuming you would rather not use CSS (i.e. :nth-child(odd)) you can either:

  • use a normal for loop:

    @for (int i = 0; i < Model.Count; i++)
    {
        ...
    }
    
  • use .Select:

    @foreach (var item in Model.Select((x, i) => new { Data = x, Index = i }))
    {
        ...
    }
    

Either way, you'd have access to the current index and could then use i % 2 == 1 as the condition for your background-color. Something like:

<tr style="background-color:@(i % 2 == 1 ? "red" : "white")">...</tr>

Upvotes: 56

Dave Ward
Dave Ward

Reputation: 60580

How about something like this?

@for (int i = 0; i < Model.length; i++) {
  <tr @(i % 2 != 0 ? class="odd" : "")>
    <td>@Model[i].DisplayName</td>
    <td>@Model[i].Currency</td>
    <td>@String.Format("{0:dd/MM/yyyy}", Model[i].CreatedOn)</td>
    <td>@String.Format("{0:g}", Model[i].CreatedBy)</td>
    <td>@Html.ActionLink("Edit", "Edit", new { id = Model[i].Id })</td>
  </tr>

Upvotes: 9

Related Questions