Search code examples
asp.net-mvchtml-helpermvc-editor-templates

Create an ASP.NET MVC Html helper similar to DropDownListFor


In certain cases I want to display SelectList object not using DropDownListFor helper. Instead, I want to create a helper that iterates over the SelectListItems, and draw something different.

I have created an EditorTemplate:

@model RadioButtonOptions

<div class=" switch-field noselect" style="padding-left: 0px;">
    @foreach (SelectListItem op in Model.Values.Items)
    {
        var idLabelF = ViewData.TemplateInfo.GetFullHtmlFieldId("") + "_" + op.Value;
        var esChecked = "";

        if (op.Selected)
        {
            esChecked = "checked";
        }

        <input type="radio" id="@idLabelF" name="@(ViewData.TemplateInfo.GetFullHtmlFieldName(""))" value="@op.Value" @esChecked />
        <label for="@idLabelF" style="width: 100px;">@op.Text</label>

    }
</div>

The RadioButtonOptions class is a ViewModel:

public class RadioButtonOptions
    {
        public SelectList Values { get; set; }
    }

The final resul looks like this:

enter image description here

My ViewModel is like this (simplified):

public class MainVisitVM
{
    public MainVisit Visit { get; set; }

    public RadioButtonOptions VisitOptions { get; set; }
}

And I use it in Razor View as:

    <div class="clearfix">
        @Html.LabelFor(x=> x.Visit.Tipo)
        <div class="input">
            @Html.EditorFor(x=> x.VisitOptions ) //HERE
        </div>
    </div>

The problem I have is that I want this to work more like the DropDownListFor, so the lamda expresion I pass is the property holding the selected value, and then just pass the SelectList object (or a custom list).

<div class="clearfix">
    @Html.LabelFor(x=> x.Visit.Tipo)
    <div class="input">
         @Html.CustomDropDownListFor(x=> x.Visit.Tipo, Model.VisitOptions ) //This would be ideal!!
    </div>
</div>

So, I think doing this using EditorTemplates will not be possible. Any idea in how to accomplish this?


Solution

  • Thanks to @StephenMuecke suggestion, I ended up with this HtmlHelper extension method:

    public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
               this HtmlHelper<TModel> htmlHelper,
               Expression<Func<TModel, TProperty>> expression,
               SelectList listOfValues)
            {
    
                string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
    
                if (listOfValues == null) return MvcHtmlString.Create(string.Empty);
    
                var wrapperDiv = new TagBuilder("div");
                wrapperDiv.AddCssClass("switch-field noselect");
                wrapperDiv.Attributes.Add("style", "padding-left: 0px;");
    
                var sb = new StringBuilder();
    
                foreach (SelectListItem item in listOfValues)
                {
                    var idLabelF = htmlFieldName.Replace(".","_") + "_" + item.Value;
    
                    var label = htmlHelper.Label(idLabelF, item.Text, new { style = "width: 100px;" }).ToHtmlString();
                    var radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = idLabelF }).ToHtmlString();
    
                    sb.AppendFormat("{0}{1}", radio, label);
                }
    
                wrapperDiv.InnerHtml = sb.ToString();
    
                return MvcHtmlString.Create(wrapperDiv.ToString());
            } 
    

    Not particulary proud of my htmlFieldName.Replace(".","_"), but works.