12

how to create an HTML Helper to Extend TextBoxFor() to add CSS style?

@Html.TextBoxFor(model => model.FirstName, new { @class = "txt" }) 
tereško
  • 58,060
  • 25
  • 98
  • 150
user584018
  • 10,186
  • 15
  • 74
  • 160
  • possible duplicate of [ASP.NET MVC - Extending TextBoxFor without re-writing the method](http://stackoverflow.com/questions/6202053/asp-net-mvc-extending-textboxfor-without-re-writing-the-method) – Chris Gessler Jun 27 '12 at 17:52

3 Answers3

24

You just need to create an extension method on HtmlHelper:

public static class MyHtmlHelpers
{
    public static MvcHtmlString MyTextBoxFor<TModel, TProperty>(
         this HtmlHelper<TModel> helper, 
         Expression<Func<TModel, TProperty>> expression)
    {
        return helper.TextBoxFor(expression, new { @class = "txt" });
    }
}

Then in your view you can use it as:

@Html.MyTextBoxFor(model => model.FirstName) 

Note: Don't forget to @using the namespace of MyHtmlHelpers if your views.

arserbin3
  • 6,010
  • 8
  • 36
  • 52
nemesv
  • 138,284
  • 16
  • 416
  • 359
  • well...thnx for the solution, Just wanted to know can I make the extension name same, means Instead of MyTextBoxFor, Can I keep the name same as TextForFor? – user584018 Jun 27 '12 at 18:06
  • You can have an extension method with the same name e.g. `TextBoxFor`, the problem is that the namespace of the built in `TextBoxFor` is included by default. So to use your extension method you need to call through the static class `MyHtmlHelpers.TextBoxFor(Html, model => model.FirstName)` otherwise the compiler cannot disambiguate. You can remove the default namespace include but then calling the builtin helpers will be problematic. – nemesv Jun 27 '12 at 18:28
  • 2
    how to accept htmlAttrbutes in the input of our HtmlHelper and add this class to them? @nemesv – MRebati Jun 21 '16 at 22:46
12
    public static System.Web.Mvc.MvcHtmlString DtxTextBoxFor<TModel, TValue>
        (this System.Web.Mvc.HtmlHelper<TModel> html,
        System.Linq.Expressions.Expression<System.Func<TModel, TValue>> expression,
        System.Collections.Generic.IDictionary<string, object> htmlAttributes = null, bool readOnly = false)
    {
        if (htmlAttributes == null)
        {
            htmlAttributes =
                new System.Collections.Generic.Dictionary<string, object>();
        }

        System.Web.Mvc.ModelMetadata oModelMetadata =
            System.Web.Mvc.ModelMetadata.FromLambdaExpression(expression, html.ViewData);

        if (oModelMetadata == null)
        {
            if (readOnly)
            {
                if (htmlAttributes.ContainsKey("readonly") == false)
                {
                    htmlAttributes.Add("readonly", "read-only");
                }
            }
        }
        else
        {
            if (htmlAttributes.ContainsKey("placeholder") == false)
            {
                string strHtmlFieldName =
                    System.Web.Mvc.ExpressionHelper.GetExpressionText(expression);

                string strLabelText =
                    oModelMetadata.DisplayName ??
                    oModelMetadata.PropertyName ??
                    strHtmlFieldName.Split('.').Last();

                if (string.IsNullOrEmpty(strLabelText) == false)
                {
                    htmlAttributes.Add("placeholder", strLabelText);
                }
            }

            if ((readOnly) || (oModelMetadata.IsReadOnly))
            {
                if (htmlAttributes.ContainsKey("readonly") == false)
                {
                    htmlAttributes.Add("readonly", "read-only");
                }
            }
        }

        htmlAttributes.Add("class", "form-control");

        System.Linq.Expressions.MemberExpression oMemberExpression =
            expression.Body as System.Linq.Expressions.MemberExpression;

        if (oMemberExpression != null)
        {
            System.ComponentModel.DataAnnotations.StringLengthAttribute oStringLengthAttribute =
                oMemberExpression.Member.GetCustomAttributes
                (typeof(System.ComponentModel.DataAnnotations.StringLengthAttribute), false)
                .FirstOrDefault() as System.ComponentModel.DataAnnotations.StringLengthAttribute;

            if (oStringLengthAttribute != null)
            {
                if (htmlAttributes.ContainsKey("maxlength") == false)
                {
                    htmlAttributes.Add("maxlength", oStringLengthAttribute.MaximumLength);
                }
            }
        }

        return (html.TextBoxFor(expression, htmlAttributes));
    }
2

Building on answer by @nemesv, here is an extension that supports htmlAttributes with additional custom attributes.

vb.net:

<Extension()>
Function MyTextBoxFor(Of TModel, TProperty)(ByVal helper As HtmlHelper(Of TModel), ByVal expression As Expression(Of Func(Of TModel, TProperty)), htmlAttributes As Object) As MvcHtmlString           
    'copy htmlAttributes object to Dictionary
    Dim dicHtmlAttributes As New Dictionary(Of String, Object)
    For Each prop in htmlAttributes.GetType().GetProperties()
        dicHtmlAttributes.Add(prop.Name,prop.GetValue(htmlAttributes))
    Next
    'add custom attribute
    dicHtmlAttributes.Add("foo","bar")

    Return helper.TextBoxFor(expression, dicHtmlAttributes)
End Function

c#:

public static MvcHtmlString MyTextBoxFor<TModel, TProperty>(
     this HtmlHelper<TModel> helper, 
     Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
    // copy htmlAttributes object to Dictionary
    Dictionary<string, object> dicHtmlAttributes = new Dictionary<string, object>();
    foreach (var prop in htmlAttributes.GetType().GetProperties())
    {
        dicHtmlAttributes.Add(prop.Name, prop.GetValue(htmlAttributes));
    }
    //add custom attribute
    dicHtmlAttributes.Add("foo", "bar");
    return helper.TextBoxFor(expression, dicHtmlAttributes);
}
Ross
  • 2,123
  • 1
  • 18
  • 18