Twitter About Home

Simplify Iteration in Your MVC Views

*This is just a simple little tip, but it may come in handy if you frequently iterate over collections in your ASP.NET MVC views. *

Published Aug 31, 2009

How often do your ASP.NET MVC views need to iterate over a collection to render some HTML for each item? For example, if your model is a collection of Person objects, and you want to render a table of them, you might write view code as follows:


A few bits of this code make me uncomfortable:

  • In order to render “even” and “odd” and “last” CSS classes, I used a series of inline ternary operators, which obscures the readability of the HTML.
  • Just so I could render the index number of each item, I used a for loop instead of the syntactically tidier foreach loop.
  • To work out which item was the last one (so I could render a special “last” CSS class), I used ToList() to evaluate the whole collection up-front and store it in a temporary variable, then manually compared each item’s index with the index of the final item, remembering to subtract one because the indexes are zero-based. Fiddly manual work.

So, how about the following alternative syntax?


Admittedly it’s not radically different, but I think the simplification is worth it. No more kludgy temporary variable, no more manually working out the position of the final item, and no more ugly series of inline ternary operators.

The .ToDescriptiveList() helper

To make the .ToDescriptiveList() helper available in your own application, first download the helper classes and add them to your solution. If you’re putting them into a namespace not normally referenced by your views, you’ll need to import their namespace by adding the following to your web.config file:

            <!-- leave rest as-is - just add the following: -->
            <add namespace="DescriptiveListHelper"/>

Now, if you add .ToDescriptiveList() on to the end of any IEnumerable in a view, you’ll get an enumerable of objects with the following methods/properties:

Method/Property Type Description
Item Your model type The item in your underlying enumerable
Index int The zero-based index of the item in your underlying enumerable
Description ItemDescription flags Bit flags enum with one or more of the following values: First, Last, Interior, Odd, Even
Is(ItemDescription) bool True if the item matches the specified description; false otherwise. Example:

<% if (item.Is(ItemDescription.Last)) { %> … <% } %>
CssClass() string Generates a CSS class name based on the Description property. This makes it easy to style first, last, or alternate rows differently without manually constructing a CSS class name using <% if %> or ternary operators in your view code. If you wish, you can pass as a parameter to specify a CSS class name prefix.

That’s all there is to it.

A note about NVelocity and its Fancy Loops syntax

I made this helper because I got jealous of NVelocity’s fancy loops syntax which at first glance appears to make iteration in views so neat and simple. So, I spiked a simple way to use similar syntax in ASPX views, but having done it, realised that there are many scenarios where this syntax is inadequate or forces you to repeat yourself (e.g., in tables, when the row markup varies by odd/even, but a certain column varies by first/last or index). That’s why, in the end, I settled on the more basic but more flexible option of just annotating a collection with first/last/odd/even/index information.

A note about jQuery and/or CSS 3

With jQuery or with CSS 3, you can use pseudoclasses such as :first, :last, :even, and :o dd to style items by their position in a collection of DOM nodes. If you have the luxury of being able to rely on these, great, otherwise you might need a server-side solution such as the one I’ve presented here.


Writing Great Unit Tests: Best and Worst Practices

This blog post is aimed at developers with at least a small amount of unit testing experience. If you’ve never written a unit test, please read an introduction and have a go at it first.

Published Aug 24, 2009