Wednesday, January 27, 2010

ASP.NET MVC links for jQuery tabs

To work fully, including the loading indicator when using AJAX tab loading, jQuery expects your tab set up to be something like:

<div id="tabs">
<ul>
<li><a href="/controller/action1"><span>Tab 1</span></a></li>
<li><a href="/controller/action2"><span>Tab 2</span></a></li>
<li><a href="/controller/action3"><span>Tab 3</span></a></li>
</ul>
</div>

Note that the standard HtmlHelper extension for a link has trouble producing the correct anchor tag. If you specify HTML in the link text, it will be encoded on output. This is decidedly not what you want.


After several project where I used jQuery to wrap the anchor text in a span on page load, I decided that it would be just as easy (perhaps easier) to simply add a new extension named TabLink to my existing collection of extensions and simply generate the anchors with the embedded span for tab links.



public static string TabLink( this HtmlHelper helper, string text, string action )
{
return TabLink( helper, text, action, null, null, null );
}

public static string TabLink( this HtmlHelper helper, string text, string action, string controller )
{
return TabLink( helper, text, action, controller, null, null );
}

public static string TabLink( this HtmlHelper helper, string text, string action, string controller, object htmlAttributes )
{
return TabLink( helper, text, action, controller, null, htmlAttributes );
}

public static string TabLink( this HtmlHelper helper, string text, string action, string controller, object routeValues, object htmlAttributes )
{
var urlHelper = new UrlHelper( helper.ViewContext.RequestContext );

var anchorBuilder = new TagBuilder( "a" );
anchorBuilder.Attributes.Add( "href", urlHelper.Action( action, controller, routeValues ) );
anchorBuilder.MergeAttributes( new ParameterDictionary( htmlAttributes ), true );

var spanBuilder = new TagBuilder( "span" );
spanBuilder.SetInnerText( text );

anchorBuilder.InnerHtml = spanBuilder.ToString( TagRenderMode.Normal );

return anchorBuilder.ToString( TagRenderMode.Normal );
}


Used as:


<div id="tabs">
<ul>
<li><%= Html.TabLink( "action1" ) %></li>
<li><%= Html.TabLink( "action2", "controller" ) %></li>
<li><%= Html.TabLink( "action3", "controller", new { id = "tab3" } %></li>
<li><%= Html.TabLink( "action4", "controller", new { page = 1 }, new { id = "tab4" } %></li>
</ul>
</div>


<script type="text/javascript">
$(function() {
$('#tabs').tabs();
});
</script>