Geeks With Blogs
Tyson's Blog

My coworker and I were working a little later than our teammates this evening, and while reflecting on this week's work, we discovered this gem thanks to the venerable ReSharper and its code analysis (it detected an unclosed tag):

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Product>>" %>

<div class="product-table grid">
    <% var i = 0;
       var j = 0;
       foreach (var item in Model)
       { %>
        <% if (i % 4 == 0)
           { %>
                    <% if (j != 0)
                     { %></div><% } %>
                    <div class="products-row">
        <% } %>
        <%= Html.DisplayFor(x => item) %>
        <% i++;
            j++;
        } %>
    </div>
</div>

I've edited this slightly to keep it a bit more anonymous. This, folks, is how not to do a template. I'm not trying to embarrass anyone here; this was likely originally done under the gun with the thought that we could clean it up later. Unfortunately, looking at our history, instead of being cleaned up, it's been modified and made worse several times.

If you didn't have a way to get this to render, it would probably take you a bit to figure out what it's actually doing. If you want me to save you the time, it's taking a collection of Products and displaying them in rows of 4 items each. This code is a problem for me because I subscribe to the clean, short, and easy-to-read philosophy. If the single-letter variables and their use wasn't enough to make you cringe, the broken HTML right there in the middle should. That's precisely the type of thing we want to avoid, and I'm glad ReSharper brought it to our attention. In a few minutes, we had replaced the above with this:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Product>>" %>
<%@ Import Namespace="Extensions" %>
<div class="product-table grid">
    <% foreach (var groupOfFour in Model.GroupsOf(4))
       { %>
    <div class="products-row">
        <%= Html.DisplayForMany(x => groupOfFour) %>
    </div>
    <% } %>
</div>

I don't know about you, but I can figure out that little template pretty quickly. You'll notice we have a couple new methods there which we pulled out for reusability: .GroupsOf() and .DisplayForMany(). These are both extension methods. The latter we already had in place; it simply iterates over an enumerable and calls Html.DisplayFor each of the items. The former we created for this view:

public static IEnumerable<IGrouping<int, T>> GroupsOf<T>(this IEnumerable<T> items, int count)
{
    return items
             .Select((item, index) => new { Item: item, Index = index / count })
             .GroupBy(x => x.Index, x => x.Item);
}

Not bad, eh? :-)

Posted on Friday, November 19, 2010 10:46 PM | Back to top


Comments on this post: An Elegant MVC Template for Items in Rows

No comments posted yet.
Your comment:
 (will show your gravatar)


Copyright © TStewartDev | Powered by: GeeksWithBlogs.net