Custom DropdownList 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 DropdownList with model binding to render dropdown list control.

Following are the steps :

We have created a folder named CustomHelpers to hold our Custom helper class.


We have created a class file named CustomDropDownListModelBinding.cs to hold code for our custom helper. The class file looks like below :


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

namespace CustomHtmlHelpers.CustomHelpers
{
    public static class CustomDropdDownListModelBinding
    {
        //This overload accepts expression and inturns calls the second overload.
        public static MvcHtmlString Custom_DropdownListFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
        {
            return Custom_DropdownListFor(helper, expression, null);
        }

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

            //Created a select element which renderes the dropdown.
            TagBuilder dropdown = new TagBuilder("select");
            //Assigning the name and id attribute.
            dropdown.Attributes.Add("name", propertyName);
            dropdown.Attributes.Add("id", propertyName);

            //Created StringBuilder object to store option data fetched oen by one from list.
            StringBuilder options = new StringBuilder();
            //Iterated over the IEnumerable list.
            foreach (var item in (IEnumerable<SelectListItem>)metadata.Model)
            {
                //Each option represents a value in dropdown. For each element in the list, option element is created and appended to the stringBuilder object.
                options = options.Append("<option value='" + item.Value + "'>" + item.Text + "</option>");
            }
            //assigned all the options to the dropdown using innerHTML property.    
            dropdown.InnerHtml = options.ToString();
            //Assigning the attributes passed as a htmlAttributes object.
            dropdown.MergeAttributes(new RouteValueDictionary(htmlAttributes));
            //Returning the entire select or dropdown control in HTMLString format.
            return MvcHtmlString.Create(dropdown.ToString(TagRenderMode.Normal));
        }
    }
}


In the above class we have created two overloads as per our convenience.

Overload 1 : The first overload accepts linq expression as parameter. 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 selec tag.
          We are then iterating over the list and creating option element for each item in the list. We have appended the option elements in string format to object of StringBuilder class. This object is then added to the select element using innerHTML property. We have also assigned other attributes passed using htmlAttributes object.


ViewModel :

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


namespace CustomHtmlHelpers.Models
{
    public class Register
    {
        public List<SelectListItem> players { get; set; }
    }
}

The above is our model class. We have created a list of SelectedListItem. We will use this property to populate the dropdownlist.

Controller :



public ActionResult About()
        {
            Register register = new Register();
            List<selectlistitem> listOfPLayers = new List<selectlistitem>();
            listOfPLayers.Add(new SelectListItem { Text = "Jack Wilshere", Value = "10" });
            listOfPLayers.Add(new SelectListItem { Text = "Thierry Henry", Value = "14" });
            listOfPLayers.Add(new SelectListItem { Text = "Cesc Fabregas", Value = "04" });
            listOfPLayers.Add(new SelectListItem { Text = "Santi Cazorla", Value = "19" });
            listOfPLayers.Add(new SelectListItem { Text = "Tomas Rosicky", Value = "08" });
            register.players = listOfPLayers;
            return View(register);
        }

We have created a model object. We have created a list and assgined the model property with this list.


View :



@model CustomHtmlHelpers.Models.Register

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

<h2>About</h2>
<p>
@Html.Custom_DropdownListFor(model => model.players)
@Html.Custom_DropdownListFor(model => model.players, new { multiple = "multiple"})
</p>

UI :



The first is the normal dropdown. The econd dropdown rendered is the multi select dropdown.

Rendered HTML :

<select id="players" name="players">
<option value='10'>Jack Wilshere</option>
<option value='14'>Thierry Henry</option>
<option value='04'>Cesc Fabregas</option>
<option value='19'>Santi Cazorla</option>
<option value='08'>Tomas Rosicky</option>
</select>
<select id="players" multiple="multiple" name="players">
<option value='10'>Jack Wilshere</option>
<option value='14'>Thierry Henry</option>
<option value='04'>Cesc Fabregas</option>
<option value='19'>Santi Cazorla</option>
<option value='08'>Tomas Rosicky</option>
</select>


0 comments:

Post a Comment