Thursday, January 19, 2012

Replacement for LabelFor in ASP.NET MVC 3

As I've been deep-diving further into ASP.Net MVC 3, I ran into an issue where I needed to arbitrarily show an indicator against a label that would tell me which fields are required.  We were initially doing this by hand, but have been using a ton of inheritance to set [Required] attributes on fields.  In order to overcome this pain, we decided to create a helper method that we now use instead of @Html.LabelFor()... it looks like this (Exactly from *.cs file):

using System.Linq;
using System.Linq.Expressions;

namespace System.Web.Mvc
{
    public static class HtmlHelpers
    {
        public static MvcHtmlString LabelForRequired<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, 
            Expression<Func<TModel, TValue>> expression,
            string id="", bool generatedId=false)
        {
            var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
            var htmlFieldName = ExpressionHelper.GetExpressionText(expression);

            if (metadata.IsRequired)
            {
                var labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
                if (string.IsNullOrWhiteSpace(labelText))
                {
                    return MvcHtmlString.Empty;
                }

                var tag = new TagBuilder("label");
                var spanTag = new TagBuilder("span");
                spanTag.AddCssClass("required");
                spanTag.SetInnerText("*");

                if (!string.IsNullOrWhiteSpace(id))
                {
                    tag.Attributes.Add("id", id);
                }
                else if (generatedId)
                {
                    tag.Attributes.Add("id", htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName) + "_Label");
                }


                tag.Attributes.Add("for", htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
                tag.SetInnerText(labelText);

                return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal) + "&nbsp;" + spanTag.ToString(TagRenderMode.Normal));
            }
            else
            {
                return System.Web.Mvc.Html.LabelExtensions.LabelFor(htmlHelper, expression);
            }
        }
    }
}


Hope that this helps someone...