Saturday, December 3, 2011

Learning MVC: Custom Html Helpers

Html helpers are used to render HTML and, in most cases, return a string which is then rendered as part of web page. The underlying idea is to reduce development work, decrease the amount of typing and generally provide a readable markup. However, I quickly found that the helpers provided with the MVC framework are small in number. Fortuantely, it is relatively easy to write your own html helpers. There are several ways to do it, but so far I liked extending the HtmlHelper class the best. There are a couple of "gotchas" there, but after that it looks elegant and efficient.

I started with creating a folder in my solution called "HtmlHelpers" and creating the Helpers.cs class there. The class is part of the namespace "HtmlHelpers". The first "gotcha", or two, is to add the namespace to the Web.config file. The second, smaller "gotcha" is that it may not be enough to add it to the main Web.config class. If, for example, the helper is used by the view which resides in the Views folder, then the Web.config in the Views folder (if it exists) also needs to have the namespace registered.

<pages>
<namespaces>
<add namespace="System.Web.Helpers"/>
<add namespace="System.Web.Mvc"/>
<add namespace="System.Web.Mvc.Ajax"/>
<add namespace="System.Web.Mvc.Html"/>
<add namespace="System.Web.Routing"/>
<add namespace="System.Web.WebPages"/>
<add namespace="HtmlHelpers"/>
</namespaces>
</pages>

Both the class and the extension methods have to be static. The type of the extension method can not be "string" - that's another "gotcha". The engine will escape all the HTML tags by default. This is why the HtmlString should be returned. That was my last "gotcha". Here's the whole class:


namespace HtmlHelpers
{
public static class Helpers
{
public static IHtmlString BulletedList(this HtmlHelper helper, string data)
{
string[] items = data.Split('|');

var writer = new HtmlTextWriter(new StringWriter());
writer.RenderBeginTag(HtmlTextWriterTag.Ul);

foreach (string s in items)
{
writer.RenderBeginTag(HtmlTextWriterTag.Li);
writer.Write(helper.Encode(s));
writer.RenderEndTag();
}

writer.RenderEndTag();
return new HtmlString(writer.InnerWriter.ToString());
}

public static IHtmlString Paragraph(this HtmlHelper helper, string text)
{
return new HtmlString("<p>" +text + "</p>");
}
}
}

The first method takes strings delimited by "|" character and creates a bulleted list from them. Here I used HtmlTextWriter. In the second method I've shown that the HtmlTextWriter is not absolutely necessary - it is possible to just add tags "by hand".

This kind of usage

@Html.Paragraph("A custom paragraph")
@Html.BulletedList("Item 1|Item 2|Item 3|Item 4")

Provides the following output

References:

Custom HtmlHelper Renders Text and not Markup
Understanding HTML Helpers by . Also posted on my website

No comments: