Create a custom HtmlHelper.TextBoxFor() to display label text as “placeholder” integrated with twitter bootstrap

We have TextBoxFor() and LabelFor() in MVC, they are binded with my model. If you are using twitter bootstrap and want to display the model property label as a placeholder in textboxes, what should you do.

Here is what I have done.

My model:

public class User
{
    [Display(Name="User name")]
    public string Username {get;set;}
}

Normally in the view we put,

@model User

<ol>
    <li>
        @Html.LabelFor(p=&gt;p.Username)
        @Html.TextBoxFor(p=&gt;p.Username)
    </li>
</ol>

image

If you want to display it as placeholder in twitter bootstrap,

image

Let’s create a TextBoxPlaceHolderFor() extension method of the htmlhelpers, remember to reference the namespace,

using System.Web.Mvc.Html;

So you can re-use the HtmlHelper.TextBoxFor() in your TextBoxPlaceHolderFor() method.

Here is the code with three overloads,

public static class TextBoxForExtensions
    {
        public static MvcHtmlString TextBoxPlaceHolderFor(this HtmlHelper html, Expression<Func> expression, object htmlAttributes)
        {
            var dict = new RouteValueDictionary(htmlAttributes);
            return html.TextBoxPlaceHolderFor(expression, dict);
        }
        public static MvcHtmlString TextBoxPlaceHolderFor(this HtmlHelper html, Expression<Func> expression)
        {
            var htmlAttributes = new Dictionary();
            return html.TextBoxPlaceHolderFor(expression, htmlAttributes);
        }

        public static MvcHtmlString TextBoxPlaceHolderFor(this HtmlHelper html, Expression<Func> expression, IDictionary 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))
            {
                if (htmlAttributes == null )
                {
                    htmlAttributes = new Dictionary();
                }
                htmlAttributes.Add("placeholder", labelText);
            }
            return html.TextBoxFor(expression, htmlAttributes);
        }

    }

When you call the methods you can do,

@Html.TextBoxPlaceHolderFor(m => m.UserName)

//or 

@Html.TextBoxPlaceHolderFor(m => m.UserName, new { @class="form-field" })


You are done. Now get your form neat and clean using the TextBoxPlaceHolderFor().

Advertisements

An extension method to create a SelectList, make your code neat & clean in MVC

When you have an IEnumerable model list bind to a select list items, you always need to write

var Items = Service.FindAll().Select(p => new SelectListItem() { Text = p.Name, Value = p.Id });

Here I create a extension method of IEnumerable<T> called “ToSelectList”,

    public static class SelectListExtensions
    {
        public static IEnumerable<SelectListItem> ToSelectList<T>(this IEnumerable<T> items,
            Func<T,string> text, Func<T,string> value = null, Func<T,Boolean> selected = null)
        {
            return items.Select(p => new SelectListItem
            {
                Text = text.Invoke(p),
                Value = (value==null? text.Invoke(p): value.Invoke(p)),
                Selected = selected == null? false: selected.Invoke(p)
            });
        }
    }

When you read the list from database and bind to a select list, you can write this way,

var Items = Service.FindAll().ToSelectList(p=>p.Name, p=>p.Id);

LabelFor html helper with htmlAttributes, MVC 3

The default LabelFor() html helper only comes with two overloads.

Html.LabelFor(Expression expression)

Html.LabelFor(Expression expression, string labelText)

Here is the extension came handy when you want to apply style sheet classes to the label.

public static class LabelForExtensions
    {
        
        public static MvcHtmlString LabelFor(this HtmlHelper html, Expression<Func> expression, object htmlAttributes)
        {
            return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
        }
        public static MvcHtmlString LabelFor(this HtmlHelper html, Expression<Func> expression, IDictionary 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));
        }

    }

Call it in the view by using the following line of code.

@Html.LabelFor(a => a.Name, new { @class="field-label",title="Enter Username"})

The output is,

Username