William Duffy

Glasgow Based C# ASP.NET Web Developer

Alternating Row Colours in MVC Views

Alternating row colours on tabular data is one of the most common data visualisation styles a web developer has to implement. Almost every project I have built required tabular data, and alternating row colours were key to the clean, easily readable presentation of that data.

However, it quickly becomes tiresome writing the logic to work out which rows are odd/even and change css classes on every table/project, not to mention it breaks the DRY principle. A further issue arises from the MVC pattern’s recommendation that views should be dumb and have low cyclomatic complexity.

To get around both these issues, and in the process gain an abstracted, reusable method of alternating the row colours we can create an extension method. This extension method, when implemented against the IList interface, allows for its use on any concrete collection which implements that interface.

namespace System.Collections
{
  public static class IListExtensions
   {
 
    public static string GetRowClass(this IList list, object item, string evenClass, string oddClass = "")
     {
      int index = list.IndexOf(item);
      return index % 2 == 0 ? evenClass : oddClass;
     }
 
   }
}

To alternate row colours in your view it’s simply a case of calling the extension method and passing in the relevant classes for odd/even rows.

<table class="formattedTable" cellspacing="0">
 <tr>
  <th>Name</th>
  <th>Business</th>
  <th>Email</th>
 </tr>
 <% foreach (var c in Model.Contacts) { %>
 <tr class="<%: Model.Contacts.GetRowClass(c, "evenRow", "oddRow") %>">
  <td><%: c.Fullname %></td>
  <td><%: c.Business %></td>
  <td><%: c.Email)%></td>
 </tr>
 <% } %>
</table>

I have put the extension method into the System.Collection namespace so that I only have to reference my extension method library in the project to access it, however if you are uncomfortable with this you can easily put it into your own namespace and import it manually.

Also, notice that I am using C# 4′s optional parameters on the oddClass parameter. A lot of times I only style one row and leave the other transparent so this allows for slightly neater view markup. If you aren’t using C# 4 you can simply overload the extension method.


Tagged as , , , , , , , , + Categorized as ASP.NET, C#, HTML & CSS, MVC

8 Comments

  1. That’s actually quite a nice solution, cheers. I’ve been putting this type of logic into Views simply due to convenience but this is much nicer. Simple code :)

  2. Another way is to let the client take care of this using some jquery

    $(document).ready(function() {
    $(‘table.evenodd tr:not([th]):odd’).addClass(‘odd’);
    $(‘table.evenodd tr:not([th]):even’).addClass(‘even’);
    })

  3. I like the idea, however is IList.IndexOf not an expensive method? Would it not be better to just suck it up and use a counter?

  4. I think you are missing the point ryan.

    The only way to get a self populated index in here would be to pass it in yourself – there is no loop inside the method. Thus you’d rely on the builder of your view to have a counter. Then having to maintain that counter, manually as well, starts to be expensive, especially if they don’t know what they are doing.

    Or you could use jQuery to do it:

    $(“ul li:nth-child(even)”).addClass(“evenRow”);
    $(“ul li:nth-child(odd)”).addClass(“oddRow”);

    But William’s method takes away the pain of knowing all these wee tricks programmers use. I was quoted just recently:

    “the whole point of mvc is decoupling the view from the code”

    so any sort of logic, like jQuery, would break that paradigm. Well done William, keep it clean and simple.

  5. This piece of code looks like what I did as a student in JSP 10 years ago. is MVC worth it? Wouldn’t it be a lot easier to use a Repeater?

  6. @Tsashi MVC is a design pattern that has been around for a long time, and has been used in Java extensively, it’s not unique to ASP.NET. Repeaters are great for quick webform work however they are tightly coupled to the webform model and as a result are extremely difficult to unit test. There is a lot of discussions on the web comparing ASP.NET webforms to ASP.NET MVC which I would recommend you have a read at if you can.

  7. So, I am a n00b when it comes to MVC and .NET in general, but I seem to be having a library inclusion issue. It doesn’t matter whether I put the extension in my own namespace or the System.Collections namespace.

    Here is the error that I get.

    CS1928: ‘System.Collections.Generic.IList’ does not contain a definition for ‘GetRowClass’ and the best extension method overload ‘WebUI.CustomExtensions.IListExtensions.GetRowClass(System.Collections.IList, object, string, string)’ has some invalid arguments

    Any assistance would be greatly appreciated. Thanks!

  8. Sorry, I figured it out… After some searching I learned that I was wanting to extend the generic version of IList that takes a parameter from the IList form.

    So, what does work for me is a slightly different syntax for the GetRowClass method. Here is my version in case someone is interested and thanks for the initial work, it works great!

    public static string GetRowClass(this IList list, T item, string evenClass, string oddClass = “”) where T : new()
    {
    int index = list.IndexOf(item);
    return index % 2 == 0 ? evenClass : oddClass;
    }

Leave a Reply