Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to extend MVC3 Label and LabelFor HTML helpers?

Html.Label and Html.LabelFor helper methods do not support the htmlAttributes parameter like most of the other helpers do. I would like to set the class however. Something like this:

Html.LabelFor(model => model.Name, new { @class = "control-label" })

Is there an easy way of extending Label/LabelFor without resorting to copying and extending the ILSpy disasm output of those methods?

like image 201
batkuip Avatar asked Mar 27 '12 08:03

batkuip


2 Answers

You can easily extend the label by creating your own LabelFor:

Something like this should do what you need

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));
  tag.SetInnerText(labelText);
  return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
}

Update To use the extension method just created in your project, add this line in your Views\web.config

<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="MyProject.Helpers" />   <-- my extension

    ...

 </namespaces>
</pages>
like image 150
Iridio Avatar answered Oct 21 '22 21:10

Iridio


public static class LabelExtensions
{
    public static IHtmlString LabelFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        string labelText,
        object htmlAttributes
    )
    {
        var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
        var htmlFieldName = ExpressionHelper.GetExpressionText(expression);
        return LabelHelper(htmlHelper, metadata, htmlFieldName, labelText, htmlAttributes);
    }

    public static IHtmlString Label(this HtmlHelper htmlHelper, string expression, string labelText, object htmlAttributes)
    {
        var metadata = ModelMetadata.FromStringExpression(expression, htmlHelper.ViewData);
        return LabelHelper(htmlHelper, metadata, expression, labelText, htmlAttributes);
    }

    private static IHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName, string labelText, object htmlAttributes)
    {
        string str = labelText ?? (metadata.DisplayName ?? (metadata.PropertyName ?? htmlFieldName.Split(new char[] { '.' }).Last<string>()));
        if (string.IsNullOrEmpty(str))
        {
            return MvcHtmlString.Empty;
        }
        TagBuilder tagBuilder = new TagBuilder("label");
        tagBuilder.Attributes.Add("for", TagBuilder.CreateSanitizedId(html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName)));
        var attributes = new RouteValueDictionary(htmlAttributes);
        tagBuilder.MergeAttributes(attributes);
        tagBuilder.SetInnerText(str);
        return new HtmlString(tagBuilder.ToString(TagRenderMode.Normal));
    }
}

and then:

@Html.LabelFor(x => x.SomeProperty, null, new { @class = "foo" })

or:

@Html.Label("SomeProperty", null, new { @class = "foo" })
like image 30
Darin Dimitrov Avatar answered Oct 21 '22 20:10

Darin Dimitrov