Once helper for ASP.NET MVC

Here’s an ASP.NET MVC HTML Helper that helps in the following scenario. Let’s say you have a partial that can be included a number of times in a view but has a bit of common code that need only be included once. Typically that bit of common code would be some script.

In ASP.NET such a scenario is addressed by RegisterClientScriptBlock. In the Spark View Engine it’s taken care of by the once attribute.

So, inspired by Phil Haack’s Templated Razor Delegates post from earlier this year I knew you could write helper functions for Razor that could take arbitrary markup. The key to it is taking a Func argument that returns a HelperResult.

To use it you invoke it like so:

@Html.Once("some unique key", @<div>arbitrary markup that gets rendered just once</div>)

More typically, for including script, e.g.:

@Html.Once("TABLE_SORTER_INIT_SCRIPT", @<script type="text/javascript">
    $(function() {
        $('table.sortable th').each(function(){
            // . . .
        });
    });
</script>)

Here’s the implementation that adds the Once extension method to HtmlHelper:

using System;
using System.Web.Mvc;
using System.Web.WebPages;

namespace Foo
{
    public static class HtmlUtils
    {
        public static HelperResult Once(this HtmlHelper html, string key, Func<object, HelperResult> template)
        {
            var httpContextItems = html.ViewContext.HttpContext.Items;
            var contextKey = "HtmlUtils.Once." + key;
            if (!httpContextItems.Contains(contextKey))
            {
                // Render and record the fact in HttpContext.Items
                httpContextItems.Add(contextKey, null);
                return template(null);
            }
            else
            {
                // Do nothing, already rendered something with that key
                return new HelperResult(writer => { /*no-op*/ });
            }
        }
    }
}

Hope that helps!

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.