Because empty tags are bad

By eidias on (tags: mvc, categories: code)

Well, not always, but there are times when they are so…what can I do to avoid them.

Up to asp.net mvc 3 there’s a problem – if I want to render something wrapped in let’s say a paragraph, but I don’t want that paragraph to appear if the content is empty, then the markup looks like this:

   1: @if (!string.IsNullOrEmpty(content)) {
   2:     <p>@content</p>
   3: }

That’s a bit verbose. If I skip that check, then an empty hole is rendered on the page so again – not good.

What I came up with today is this:

   1: @Html.SafeWrap(@<text>@content</text>)

The <text> tags are Razors way of saying render pure so as a result, this will render just the value of content variable. The nice thing about this is that you can do things like this:

   1: @Html.SafeWrap(
   2:     @<text>
   3:         <h2>@title</h2>
   4:         <span class="hint">@hint</span>
   5:         <blockquote>@content</blockquote>
   6:     </text>, "div", new { @class = "fancy" })

The two last parameters are optional and have defaults but are there for greater flexibility. So without further ado, here’s the code:

   1: public static class HtmlHelperExtensions
   2: {
   3:     public static IHtmlString SafeWrap(this HtmlHelper html, Func<ViewContext, HelperResult> innerHtml, string tagName = "p", object attributes = null)
   4:     {
   5:         return SafeWrap(html, innerHtml, tagName, HtmlHelper.AnonymousObjectToHtmlAttributes(attributes));
   6:     }
   7:     
   8:     public static IHtmlString SafeWrap(this HtmlHelper html, Func<ViewContext, HelperResult> innerHtml, string tagName, IDictionary<string, object> attributes)
   9:     {
  10:         var gut = innerHtml(html.ViewContext).ToHtmlString().Trim();
  11:         if (string.IsNullOrEmpty(gut))
  12:             return MvcHtmlString.Empty;
  13:     
  14:         var builder = new TagBuilder(tagName);
  15:         builder.MergeAttributes(attributes, true);
  16:         builder.InnerHtml = gut;
  17:     
  18:         return new MvcHtmlString(builder.ToString());
  19:     }
  20: }

Cheers