Monday, February 2, 2009

Repeater with separator for ASP.NET MVC

Today I needed to repeat over a list of items in my views, separating each item with some html. A simple foreach is no good in this case. I really liked Phil Haack's code-based repeater syntax, but it handles only alternating items, not separators. I didn't need the alternating items, so I just wrote this extension with separator support:

public static class HtmlHelperRepeatExtensions {
    private static Func<T, U> ActionToFunc<T, U>(Action<T> a) {
        return t => {
            a(t);
            return default(U);
        };
    }

    private static Func<T> ActionToFunc<T>(Action a) {
        return () => {
            a();
            return default(T);
        };
    }

    public static void Repeat<T>(this HtmlHelper html, IEnumerable<T> items, Action<T> render, Action separator) {
        var frender = ActionToFunc<T, int>(render);
        var fseparator = ActionToFunc<int>(separator);
        items.Select<T, Func<int>>(e => () => frender(e)).Intersperse(fseparator).Select(f => f()).ToArray();
    }

    // From http://blogs.msdn.com/wesdyer/archive/2007/03/09/extending-the-world.aspx
    private static IEnumerable<T> Intersperse<T>(this IEnumerable<T> sequence, T value) {
        bool first = true;
        foreach (var item in sequence) {
            if (first)
                first = false;
            else
                yield return value;
            yield return item;
        }
    }
}

Sample usage:

<% Html.Repeat(Model.Products, p => { %> 
    <div><%= p.Id%></div>
    <div><%= p.Name%></div>
<%}, () => { %> 
    <br /> <%-- separator --%>
<% }); %>

It's worth mentioning that I had to convert the rendering Actions into Funcs in order to write this in a functional style... in F# this would definitely look prettier :-)

2 comments:

hvm said...

Hi,

i m new in in MVC

I want to use this functionality in my application but so many error occur.
Please provide me sample of this blog via mail.

Shimmy said...

Can you please translate the html to razor?