views:

2314

answers:

4

When using an ASP.NET WebForms ListView control to display data in an HTML table I use the following technique in to "stripe" the table rows:

<ItemTemplate>
    <tr class="<%# Container.DisplayIndex % 2 == 0 ? "" : "alternate" %>">
        <!-- table cells in here -->
    </tr>
</ItemTemplate>

With the following CSS:

tr.alternate
{
    background-color: #EFF5FB;
}

I have just gone through the ASP.NET MVC Movie Database Application tutorial and learnt that in MVC-land table rows can be (must be?) constructed as follows:

<% foreach (var item in Model) { %>
    <tr>
        <td>
            <%= Html.Encode(item.Title) %>
        </td>
        <!-- and so on for the rest of the table cells... -->
    </tr>
<% } %>

What can I add to this code to stripe the rows of my table?

Note: I know that this can be done using jQuery, I want to know if it can be done another way.

Edit

If jQuery (or equivalent) is in your opinion the best or most appropriate post, I'd be interested in knowing why.

A: 

After some thinking, I have come up with this approach, which works but seems very clunky:

<% List<MovieApp.Models.Movie> movies = Model.ToList();
   for (int i = 0; i < movies.Count; i++)
   {
       MovieApp.Models.Movie item = movies[i];
%>
    <tr class='<%= i % 2 == 0 ? "" : "alternate" %>'>
        <td>
            <%= Html.Encode(item.Title) %>
        </td>
        <!-- and so on for the rest of the table cells -->
    </tr>
<% } %>

An alternative would be to create an anonymous type based on Movie that adds a boolean property that gets set to indicate odd/even-ness. Again, this seems far from ideal.

Richard Ev
+7  A: 

What about an extension method?

public static void Alternate<T>(this IEnumerable<T> items, Action<T, bool> action)
{
    bool state = false;
    foreach (T item in items)
        action(item, state = !state);
}

This way you could say:

<% movies.Alternate((movie, alt) => { %>
  <tr class="<%= alt ? "alternate" : "" %>">
    <td>
        <%= Html.Encode(movie.Title) %>
    </td>
    <!-- and so on for the rest of the table cells... -->
  </tr>
<% }); %>

Edit, additionally if you want the index, you can use an extension method like this:

public static void Each<T>(this IEnumerable<T> items, Action<T, int> action)
{
    int state = 0;
    foreach (T item in items)
        action(item, state++);
}
meandmycode
Wow - OK, but how do I get hold of the properties of each movie (item variable in the code of my post)?(I updated my original question to show this)
Richard Ev
Hi Richard, thats the first argument of the Action lambda, I called it movie in my example.. the part where it says: (movie, alt) are the argument names, the first argument 'movie' is the item, and alt is a boolean to indicate if this is an alternate row or not. You can change the parameter names.
meandmycode
(I've updated my example to show you what I mean).
meandmycode
Also see http://msdn.microsoft.com/en-us/library/bb397687.aspx if you've not used lambdas in c# before.
meandmycode
+19  A: 

Another option that doesn't involve lambdas and is a bit cleaner than what you got working might be this...

<% int i=0; foreach (var item in Model) { %>
    <tr class="<%= i++ % 2 == 0 ? "alternate" : "" %>">
        <td>
            <%= Html.Encode(item.Title) %>
        </td>
        <!-- and so on for the rest of the table cells... -->
    </tr>
<% } %>
Joel Mueller
Thanks for the drive-by -1. The OP seemed uncomfortable with the extension method approach, he called his own solution clunky, so I suggested an option that doesn't use extension methods, and is less clunky. For this I get downvoted?
Joel Mueller
I for one, found your solution much simpler and perfectly suited to my own application.
Praveen Angyan
I, too, liked your solution. +1 as far as I'm concerned.
luckyllama
A: 

How about this:

<% foreach (var item in Model.Alternating("alternate","") { %>
<tr class="<%= item.ClassName %>">
    <td>
        <%= Html.Encode(item.Model.Title) %>
    </td>
    <!-- and so on for the rest of the table cells... -->
</tr>

<% } %>

Which uses this extension method:

 public class AlternatingItem<T> 
  {
   public string ClassName { get; set; }
   public T Model { get; set; }
  }
  public static IEnumerable<AlternatingItem<T>> Alternating<T>(this IEnumerable<T> model, string oddString, string evenString) 
  {
   int i = 0;
   var query = from x in model
      let c = i++ % 2 == 0 ? oddString : evenString
      select new AlternatingItem<T>() { ClassName = c, Model = x };
   return query;
  }
AndyD