MVC4 enum and radio button list

asp.net Mvcasp.net Mvc-4

asp.net Mvc Problem Overview


I have seen a few threads on this but none seem to apply to MVC4 because the RadioButtonFor html extension method/helper does not exist.

Say I have an enum list - i.e Airlines:

public enum Airlines
{
   Unknown = 0,
   BritishAirways = 1,
   VirginAtlantic = 2,
   AirFrance = 3
}

How can I bind this to a Radio button list on my view and be able to retrieve the selected item? What about being able to say "select one item" if there is no selection made?

asp.net Mvc Solutions


Solution 1 - asp.net Mvc

You can create a custom Editor Template for the enum Airlines that will render a radio button list. In your Model you will have a property of type Airlines and tag this property with the Required attribute and set ErrorMessage = "select one item". Don't forget to include the jQuery validation for client side validation if you want it, usually just have to add @Scripts.Render("~/bundles/jqueryval") on your Layout or View. If you don't use the jQuery validation you will need to make the property nullable on the model because enums are just set to the first value by default so MVC will not see it as invalid. Remember if you change the property to nullable you will also need to change the Model type of your Editor Template to nullable as well.

UPDATE

To enable the Editor Template to render a radio button list for any enum, change the template to the following:

@model Enum
@foreach (var value in Enum.GetValues(Model.GetType()))
{
    @Html.RadioButtonFor(m => m, value)
    @Html.Label(value.ToString())
}

ORIGINAL

The Editor Template, Airlines.cshtml, in the Views\Shared\EditorTemplates directory:

@model MvcTest.Models.Airlines
@foreach (var value in Enum.GetValues(typeof(MvcTest.Models.Airlines)))
{
    @Html.RadioButtonFor(m => m, value)
    @Html.Label(value.ToString())
}

The Model:

public class TestModel
{
    [Required(ErrorMessage = "select one item")]
    public Airlines Airline { get; set; }
}

The action methods:

public class HomeController : Controller
{
    [HttpGet]
    public ActionResult Index()
    {
        return View(new TestModel());
    }

    [HttpPost]
    public ActionResult Index(TestModel model)
    {
        if (ModelState.IsValid)
        {
            return RedirectToAction("Index");
        }

        return View(model);
    }
}

The view:

@model MvcTest.Models.TestModel
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
@using (Html.BeginForm())
{
    @Html.EditorFor(m => m.Airline)
    <input type="submit" value="Submit" />
    @Html.ValidationSummary(false)
}

Solution 2 - asp.net Mvc

I suggest a similar approach to the other answers, but with the following editor template; EnumRadioButtonList.cshtml, in the Views\Shared\EditorTemplates directory:

@model Enum
@foreach (var value in Enum.GetValues(Model.GetType()))
{
    var id = TagBuilder.CreateSanitizedId(string.Format(
        "{0}_{1}_{2}", ViewData.TemplateInfo.HtmlFieldPrefix, Model.GetType(), value));
    <div>
        @Html.RadioButton(string.Empty, value, value.Equals(Model), new { id })
        @Html.Label(value.ToString(), new { @for = id })
    </div>
}

The HTML id of each radio button needs to be unique. Therefore the above code prefixes the id with the bound property's name by means of using ViewData.TemplateInfo.HtmlFieldPrefix. This ensures unique ids if the model contained multiple properties that used this enum, and if this editor template was used for each of them.

The accompanying label for each radio button will have its for attribute correctly set. This means that the user can select a radio button by clicking the label text, a much bigger and better click target than just the radio button itself.

For MVC model binding, the radio buttons will all have their HTML name property value set to that of the property that was specified in the EditorFor call (Airline in this scenario).

To use it:

@Html.EditorFor(m => m.Airline, "EnumRadioButtonList")

Solution 3 - asp.net Mvc

What do you mean by RadioButtonFor doesn't exist? I use MVC4 and use that in my code. For a list you can set multiple to the same name

@Html.RadioButtonFor(x => x.Airlines, Airlines.Unknown)
@Html.RadioButtonFor(x => x.Airlines, Airlines.BritishAirways)
@Html.RadioButtonFor(x => x.Airlines, Airlines.VirginAtlantic)
@Html.RadioButtonFor(x => x.Airlines, Airlines.AirFrance)

these will be tied to the model so on postback you will see Airlines set to the selected item and when loading the page the matching radio button will be selected.

Solution 4 - asp.net Mvc

I was able to combine some of the approaches from other answers with some added features:

EnumRadioButtonList.cshtml

@model Enum
@foreach (var item in EnumHelper.GetSelectList(Model.GetType()))
{
    <div class="radio">
        <label>
            @Html.RadioButton(string.Empty, item.Value, Model.Equals(Enum.Parse(Model.GetType(), item.Value)))
            @item.Text
        </label>
    </div>
}

This uses EnumHelper.GetSelectList() as a sort of hack so that you can use display attributes with your enum members:

public enum TestEnum
{
    First,
    [Display(Name = "Second Member")]
    Second,
    Third
}

Usage:

@Html.EditorFor(m => m.TestEnumProperty, "EnumRadioButtonList")

Yields:

Image

I'm also using the Bootstrap radio button styles with a separate helper for the inline version:

EnumRadioButtonListInline.cshtml

@model Enum
@foreach (var item in EnumHelper.GetSelectList(Model.GetType()))
{
    <label class="radio-inline">
        @Html.RadioButton(string.Empty, item.Value, Model.Equals(Enum.Parse(Model.GetType(), item.Value)))
        @item.Text
    </label>
}

Solution 5 - asp.net Mvc

I improved the highest rated answer by asymptoticfault a bit to reflect selected values too. Save this as EnumRadioButton.cshtml to your shared views EditorTemplates folder:

@model Enum
@foreach (var value in Enum.GetValues(Model.GetType()))
{
    if (Equals(Model, value))
    {
        @Html.RadioButtonFor(m => m, value, new {@checked = "checked"})
    }
    else
    {
        @Html.RadioButtonFor(m => m, value)
    }

    @Html.Label(value.ToString())
}

Usage:

@Html.EditorFor(item => Model.MyEnumType, "EnumRadioButton")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAhmed ilyasView Question on Stackoverflow
Solution 1 - asp.net MvcasymptoticFaultView Answer on Stackoverflow
Solution 2 - asp.net MvcRichard EvView Answer on Stackoverflow
Solution 3 - asp.net MvcMatt BodilyView Answer on Stackoverflow
Solution 4 - asp.net MvcDangeresqueView Answer on Stackoverflow
Solution 5 - asp.net MvcRichieView Answer on Stackoverflow