Thursday, 25 August 2011

ASP.Net MVC3 RadioButtonListFor htmlhelper extension



Related Posts






Assume that you have an Enum and you want to show a list of radio buttons  which iterates all the possible values for Enum and let user  select one of them or you have a Boolean and want that user select yes or no .
public enum Maritalstatus
    {
        Single,
        Married,
        Divorced,
        Widowed
    }

public class PersonViewModel
    {
        public Guid id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public bool Sex { get; set; }
        public Maritalstatus Maritalstatus { get; set; }
        [DisplayName("Do you have a job?")]
        public bool IsEmployed { get; set; }
    }


In this example we want to show all the possible  Maritalstatus and let user to select one of them .also we want to know that whether user has a job or not ?
It is very painful to do all of them manually like below.
<div>
    @Html.LabelFor(x => x.Maritalstatus)
    <ul>
        <li>     
            Single @Html.RadioButtonFor(x => x.Maritalstatus, Maritalstatus.Single)
        </li>
        <li>
            Married @Html.RadioButtonFor(x => x.Maritalstatus, Maritalstatus.Married)
        </li>
        <li>
            Divorced @Html.RadioButtonFor(x => x.Maritalstatus, Maritalstatus.Divorced)
        </li>
        <li>
            Widowed @Html.RadioButtonFor(x => x.Maritalstatus, Maritalstatus.Widowed)
        </li>
    </ul>
</div>

<div>
    @Html.LabelFor(x => x.IsEmployed)
    <ul>
        <li>     
            Single @Html.RadioButtonFor(x => x.IsEmployed, true)
        </li>
        <li>
            Married @Html.RadioButtonFor(x => x.IsEmployed, false)
        </li>      
    </ul>
</div>
 I cannot say it is impossible, but who likes that? it’s better to create a helper once and use it all over of the project.
public static MvcHtmlString RadioButtonListFor<TModel, T>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, T>> expression, string ulClass = null)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
           
var name = ExpressionHelper.GetExpressionText(expression);           
string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

            var html =  new TagBuilder("ul");
            if (!String.IsNullOrEmpty(ulClass))
                html.MergeAttribute("class", ulClass);

            string innerhtml = "";

            Dictionary<string, T> myEnumDic = null;
            Dictionary<string, bool> myBoolDic = null;
           //
            if  (typeof(T).BaseType == typeof(Enum))
            {
                myEnumDic = Enum.GetValues(typeof(T)).Cast<T>().ToDictionary(currentItem => Enum.GetName(typeof(T), currentItem));
                innerhtml = RadioRow<TModel, T>(htmlHelper, fullName, innerhtml, myEnumDic);
            }
            else if (typeof(T) == typeof(bool))
            {
                myBoolDic = new Dictionary<string, bool>();
                myBoolDic.Add("Yes", true);
                myBoolDic.Add("No", false);
                innerhtml = RadioRow<TModel, bool>(htmlHelper, fullName, innerhtml, myBoolDic);
            }          
            html.InnerHtml = htmlHelper.Label(fullName).ToString() + innerhtml;
            return new MvcHtmlString(html.ToString());
        }

        private static string RadioRow<TModel, T>(HtmlHelper<TModel> htmlHelper, string fullName, string innerhtml, Dictionary<string, T> myDic)
        {
            foreach (var item in myDic)
            {
                var liBuilder = new TagBuilder("li");
                liBuilder.InnerHtml = item.Key + " " + htmlHelper.RadioButton(fullName, item.Value).ToString();
                innerhtml = innerhtml + liBuilder;
            }
            return innerhtml;
        }


And simply you can use this helper like
<div>
@Html.RadioButtonListFor(x=>x.Maritalstatus)
</div>
<div>
@Html.RadioButtonListFor(x => x.IsEmployed)
</div>

Post a Comment