Enhancing the ASP.NET MVC View fornext loop

A common problem with the default ASP.NET MVC view engine, when rendering collections in a for/next construct is the inability to easily determine where you are in the loop. For example a common way of displaying a menu is to use unordered lists and produce the following markup:

<ul class="menu>
    <li class="first"><a href="/home">Home</a></li>
    <li class="selected"><a href="/page-1">Page 1</a></li>
    <li><a href="/page-2">Page 2</a></li>
    <li class="last"><a href="/page-3">Page 3</a></li>
</ul>

With the basic for/next loop over an ICollection producing this output is rather difficult.

My solution is an extension method for ICollection that provides additional information about the loop.

public static class CollectionExtensions
{
    public static IEnumerable<LoopItem<TSource>> Loop<TSource>(this ICollection<TSource> self)
    {
        if (self == null) throw new ArgumentNullException("self");

        var index = 0;
        var count = self.Count();

        foreach (var item in self)
        {
            yield return new LoopItem<TSource>(item, index, count);
            index++;
        }
    }
}

public class LoopItem<TSource>
{
    private int _count;

    internal LoopItem(TSource item, int index, int count)
    {
        this.Value  = item;
        this.Index  = index;
        this._count = count;
    }

    public TSource Value { get; private set; }

    public int Index { get; private set; }

    public bool IsOdd
    {
        get { return !this.IsEven; }
    }

    public bool IsEven
    {
        get { return this.Index % 2 == 0; }
    }

    public bool IsFirst
    {
        get { return this.Index == 0; }
    }

    public bool IsLast
    {
        get { return this.Index == (this._count - 1); }
    }
}

With this code in place we can now do generate the menu from a collection with:

<ul>
    <% foreach(var item in menuList.Loop()) {
        var classes = "";
        if (item.IsFirst) classes += "first ";
        if (item.IsLast) classes += "last ";%>
        <li class="<%: classes %>" >
            <%: Html.ActionLink(item.Value.Action, item.Value.Title) %>
        </li>
    <% } %>
</ul>

This makes displaying lists of data with specific classes a lot easier and simplifies your views. This same piece of code can also be used for rendering tables with odd/even rows.

Enjoy!

Advertisements

Comments are closed.

%d bloggers like this: