Custom TextBox HTML Helper with model binding in MVC3 Razor

  1. In MVC3 Razor we have HTML helpers to render different controls. 
  2. Instead of using these helpers we can create our own helper classes and methods and use them as we want.
  3. The creation of custom helpers provides flexibility to change the attributes and style of the control that renders.
  4. In this article we will create Custom HTML helper for Textbox with model binding to render textbox control.

Following are the Steps :

We will create a folder to hold our Custom Helper as shown below.


In the above snapshot , we have created a CustomHelpers folder for containing all the custom helpers. In the folder we have added a new class named CustomTextBoxModelBinding.cs.

The code for Custom TextBox helper :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Linq.Expressions;

namespace CustomHtmlHelpers.CustomHelpers
{
    public static class CustomTextBoxModelBinding
    {
        //This overload accepts single expression as parameter.
        public static MvcHtmlString Custom_TextBoxFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
        {
            return Custom_TextBoxFor(helper, expression, null);
        }

        //This overload accepts expression and htmlAttributes object as parameter.
        public static MvcHtmlString Custom_TextBoxFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression,object htmlAttributes)
        {
            //Fetching the metadata related to expression. This includes name of the property, model value of the property as well.
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
            //Fetching the property name.
            string propertyName = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();

            //Creating a input tag using TagBuilder class.
            TagBuilder textBox = new TagBuilder("input");
            //Setting the tags property type to text to render textbox.
            textBox.Attributes.Add("type", "text");
            //Setting the name and id attribute.
            textBox.Attributes.Add("name", propertyName);
            textBox.Attributes.Add("id", propertyName);

            //Setting the value attribute of textbox with model value if present.
            if (metadata.Model != null)
            {
                textBox.Attributes.Add("value", metadata.Model.ToString());
            }
            textBox.MergeAttributes(new RouteValueDictionary(htmlAttributes));
            return MvcHtmlString.Create(textBox.ToString(TagRenderMode.Normal));
        }
    }
}

Overload 1 : The first overload accepts linq expression.This method is extension method and accepts object of HtmlHelper class. The first parameter adds this overload to System.Web.MVC namespace. On view we can access this method using @html. This overload in turn calls another overload. 

Overload 2 : The second overload accepts linq expression and htmlAttributes object as parameters. We have use ModelMetaData class to get all details or meta data about the expression. We get the property name and model value using ModelMetaData class.

The propertyName is used to set the name attribute of the control. We have used TagBuilder class to create input tag. We have set its type property to text to render textbox. 


ViewModel :



using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace CustomHtmlHelpers.Models
{
    public class Register
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public int Age { get; set; }

        public string City { get; set; }

        public string Email { get; set; }

        public bool IsMarried { get; set; }
    }
}

In the above code we have created a class Register which will be our model which we will pass to view.

View :




@model CustomHtmlHelpers.Models.Register

@{
    ViewBag.Title = "About Us";
}

<h2>About</h2>
<p>
    @Html.Custom_TextBoxFor(model => model.FirstName)

    @Html.Custom_TextBoxFor(Model => Model.LastName, new { maxlength = "10" })
</p>


UI :



Rendered HTML :

<input id="FirstName" name="FirstName" type="text"></input>
<input id="LastName" maxlength="10" name="LastName" type="text"></input>


Passing Model Values :

Controller :



public ActionResult About()
        {
            Register register = new Register();
            register.FirstName = "Jack";
            register.LastName = "Wilshere";
            return View(register);
        }

We have created a model object. We have assigned the values to FirstName and LastName properties.

View :



@model CustomHtmlHelpers.Models.Register

@{
    ViewBag.Title = "About Us";
}

<h2>About</h2>
<p>
    @Html.Custom_TextBoxFor(model => model.FirstName)

    @Html.Custom_TextBoxFor(Model => Model.LastName, new { maxlength = "10" })
</p>


UI :



The value which we passed in model object from controller is assigned to controls.

Rendered HTML :



<input id="FirstName" name="FirstName" type="text" value="Jack"></input>
<input id="LastName" maxlength="10" name="LastName" type="text" value="Wilshere"></input>


3 comments:

  1. How can i validate this field with data annotations?

    ReplyDelete
  2. Refer the Data Annotation section for your query. You can use Data Annotation attributes at ViewModel or model level to validate your values.

    ReplyDelete
  3. Hola probe el codigo de personalizar los @html helpers me funciona bien, lo unico que al ejecutar mi Httpost no m envie datos , por que pasa esto, en mi viista toy usando una clase que tiene propiedades a 2 clases de mi modelo???

    ReplyDelete