Variations on a simple repeater in ASP.NET MVC: A table/gallery

There are times where I've decided that I didn't want to get too deep into a mess of markup in my views, which drives me to writing a simple HtmlHelper extension method. It's a convenient and quick way to introduce slightly more robust display logic into the view.

But first off, if I may get up on my soapbox, I'd like to address the criticism around MVC views in general. I keep reading over and over again how some feel this is a step backward. That's nonsense. What we're doing in a view is not spaghetti code. We're not jumping around from place to place with data access and business rules mixed into the mess, like ASP.old. It just ain't the same thing. It's also not any worse/messy than using WebForms controls. Those are full of templates a bazillion properties to set, and you might still not get the HTML rendered that you'd really like.

In any case, let's say that I'm building a table of images. I can't just do a simple foreach loop because there are new rows to start. I could work in similar logic to what I'm about to show you in the view itself, but it won't be reusable, and will look a little messy (though really not that bad). The logic, then, is that we want to build a table, and split the series every so often to start a new row. Ignoring for a moment the markup components of a table and its rows and cells, we fundamentally only need to repeat the individual cells and end/start rows. This is my first stab at just such a helper:

public static void SeriesSplitter<T>(this System.Web.Mvc.HtmlHelper htmlHelper, IEnumerable<T> 
items, int itemsBeforeSplit, Action<T> template, Action seriesSplitter)
{
    if (items == null)
        return;
    var i = 0;
    foreach (var item in items)
    {
        if (i != 0 && i % itemsBeforeSplit == 0)
            seriesSplitter();
        template(item);
        i++;
    }
}

As you can see, there isn't much to it. The first parameter extends the HtmlHelper class (the Html property of a ViewPage), the second takes the enumerable series you want to split up, the third says how many items to display before doing the split, and finally we take some Action objects to render. We're still doing a foreach, but if we get to a number of items that's divisible by the parameter you supplied, we pop in the splitter markup as well. In the view, your markup ends up looking something like this:

<table>
    <tr>
    <% Html.SeriesSplitter(Model.Photos, 4, photo => { %>
        <td><img src="<%=ResolveUrl("~/Thumbnail.ashx?id=" + photo.ID)%>"
alt="<%=Html.Encode(photo.Title)%>" /></td>
    <%}, () => { %></tr><tr><% }); %>
    </tr>
</table>

What's particularly fun is that even the HTML validates right in Visual Studio (I take the small wins. :)). Here you can see we're making a table that does four cells at a time, and if it has to start a new row, it drops in those tr elements. Piece of cake, and still pretty clear to read.

No Comments