How can I override the @Html.LabelFor template?

40,058

Solution 1

You'd do this by creating your own HTML helper.

http://www.asp.net/mvc/tutorials/creating-custom-html-helpers-cs

You can view the code for LabelFor<> by downloading the source for ASP.Net MVC and modify that as a custom helper.


Answer added by balexandre

public static class LabelExtensions
{
    public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
    {
        return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
    }
    public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
        string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
        if (String.IsNullOrEmpty(labelText))
        {
            return MvcHtmlString.Empty;
        }

        TagBuilder tag = new TagBuilder("label");
        tag.MergeAttributes(htmlAttributes);
        tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));

        TagBuilder span = new TagBuilder("span");
        span.SetInnerText(labelText);

        // assign <span> to <label> inner html
        tag.InnerHtml = span.ToString(TagRenderMode.Normal);

        return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
    }
}

Solution 2

I expanded upon balealexandre's answer and added in the ability to specify HTML to include both before and after your label text. I added a bunch of method overloads and comments. I hope this helps folks!

Also snagged information from here: Html inside label using Html helper

namespace System.Web.Mvc.Html
{
    public static class LabelExtensions
    {
        /// <summary>Creates a Label with custom Html before the label text.  Only starting Html is provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Func<object, HelperResult> startHtml)
        {
            return LabelFor(html, expression, startHtml, null, new RouteValueDictionary("new {}"));
        }

        /// <summary>Creates a Label with custom Html before the label text.  Starting Html and a single Html attribute is provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="htmlAttributes">A single Html attribute to include.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Func<object, HelperResult> startHtml, object htmlAttributes)
        {
            return LabelFor(html, expression, startHtml, null, new RouteValueDictionary(htmlAttributes));
        }

        /// <summary>Creates a Label with custom Html before the label text.  Starting Html and a collection of Html attributes are provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="htmlAttributes">A collection of Html attributes to include.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, Func<object, HelperResult> startHtml, IDictionary<string, object> htmlAttributes)
        {
            return LabelFor(html, expression, startHtml, null, htmlAttributes);
        }

        /// <summary>Creates a Label with custom Html before and after the label text.  Starting Html and ending Html are provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="endHtml">Html to follow the label text.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Func<object, HelperResult> startHtml, Func<object, HelperResult> endHtml)
        {
            return LabelFor(html, expression, startHtml, endHtml, new RouteValueDictionary("new {}"));
        }

        /// <summary>Creates a Label with custom Html before and after the label text.  Starting Html, ending Html, and a single Html attribute are provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="endHtml">Html to follow the label text.</param>
        /// <param name="htmlAttributes">A single Html attribute to include.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Func<object, HelperResult> startHtml, Func<object, HelperResult> endHtml, object htmlAttributes)
        {
            return LabelFor(html, expression, startHtml, endHtml, new RouteValueDictionary(htmlAttributes));
        }

        /// <summary>Creates a Label with custom Html before and after the label text.  Starting Html, ending Html, and a collection of Html attributes are provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="endHtml">Html to follow the label text.</param>
        /// <param name="htmlAttributes">A collection of Html attributes to include.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, Func<object, HelperResult> startHtml, Func<object, HelperResult> endHtml, IDictionary<string, object> htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);

            //Use the DisplayName or PropertyName for the metadata if available.  Otherwise default to the htmlFieldName provided by the user.
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText))
            {
                return MvcHtmlString.Empty;
            }

            //Create the new label.
            TagBuilder tag = new TagBuilder("label");

            //Add the specified Html attributes
            tag.MergeAttributes(htmlAttributes);

            //Specify what property the label is tied to.
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));

            //Run through the various iterations of null starting or ending Html text.
            if (startHtml == null && endHtml == null) tag.InnerHtml = labelText;
            else if (startHtml != null && endHtml == null) tag.InnerHtml = string.Format("{0}{1}", startHtml(null).ToHtmlString(), labelText);
            else if (startHtml == null && endHtml != null) tag.InnerHtml = string.Format("{0}{1}", labelText, endHtml(null).ToHtmlString());
            else tag.InnerHtml = string.Format("{0}{1}{2}", startHtml(null).ToHtmlString(), labelText, endHtml(null).ToHtmlString());

            return MvcHtmlString.Create(tag.ToString());
        }
    }
}

Solution 3

LabelFor is an extension method (static) and therefore cannot be overridden. You'd need to create your own Html Helper Extension method to achieve what you require.

Share:
40,058
balexandre
Author by

balexandre

Father (x3), Husband (x1), Dedicated, Friendly. Web, Windows and Mobile developer (mostly .NET and NodeJs). Photographer by hobby, Windsurfer by passion. Born in Portugal (in 1977),happily married to a beautiful Romanian gal (since 2005) and living in Denmark (since 2006) 😊 P.S. My Simpson character was designed by a Fiverr.com user.

Updated on July 05, 2022

Comments

  • balexandre
    balexandre almost 2 years

    I have a simple field form

    <div class="field fade-label">
        @Html.LabelFor(model => model.Register.UserName)
        @Html.TextBoxFor(model => model.Register.UserName)
    </div>
    

    and this results in:

    <div class="field fade-label">
        <label for="Register_UserName">Username (used to identify all services, from 4 to 30 chars)</label>
        <input type="text" value="" name="Register.UserName" id="Register_UserName">
    </div>
    

    but I want that LabelFor code append a <span> inside so I can end up having:

    <label for="Register_UserName">
        <span>Username (used to identify all services, from 4 to 30 chars)</span>
    </label>
    

    How can I do this?

    All examples use EditorTemplates but this is a LabelFor.

  • balexandre
    balexandre over 13 years
    Got it, added the final code to my question for anyone to copy/paste/use. Thanks for the heads up.
  • Linkgoron
    Linkgoron over 13 years
    Editor templates CAN be "overriden", although they TOO are static methods.
  • Darren Lewis
    Darren Lewis over 13 years
    We're not talking about Editor templates here. An Editor template is a partial view discovered through convention. It has nothing to do with overrides or static declaration of an extension method.
  • Linkgoron
    Linkgoron over 13 years
    Yes, but when someone sees LabelFor, and then sees that it's similar to EditorFor he MIGHT think that it, too, can be overiden by convention. That's exactly what the OP asked. This has nothing to do with method overloading and static methods.
  • reaper_unique
    reaper_unique about 10 years
    I used this extension method as a start, but as it doesn't override the LabelFor method with the parameter fieldName I updated it a bit.
  • Ruchan
    Ruchan over 9 years
    How do i solve the Ambigious invocation error when using this. now there are two LabelFor methods one from the default MVC and this.
  • HaBo
    HaBo over 6 years
    @Ruchan did you ever get this fixed?
  • Ruchan
    Ruchan over 6 years
    Had to rename my own helper with different name.