Introduction
If you are familier (or learning) MVC 4, you will notice that the name of each control is generated by the MVC framework (be it Razor or Asp.Net view engine). These names are in certain formal (e.g. ParentObjectName_PropertyName) so that while posting back the form the values in the html controls are bound back to the model's (or view model's) respective properties.
This works absolutely fine with all controls except when you desire to have a radio button list, typicaly for a radio list the "name" property is same for all the radio buttons in a certain list.
The problem comes when the form is posted back, the correct value won't get mapped to the respective model (which is mapped to the radio button). Esp when you want to pass all the options/controls (whether it is selected or not, e.g. selecting a preferred address among multiple addresses entered by the user in UI )
Background
I have searched many blogs but didn't find a generic solution for radio lists. All were addressing specific problems.
Using the code
This utility needs to know what is the parent div element, under which these radio buttons reside.
Let me give you a step by step of creating this utility
1. Custom HTML Helper
Make a custom HTML helper (a static class) to make your custom HTML helper
public static class RadioButtonListHelper
{
public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object value, string parentContainer)
{
RouteValueDictionary htmlAttrs = new RouteValueDictionary();
htmlAttrs.Add("radio-list", "true");
htmlAttrs.Add("radio-list-parent", parentContainer);
return htmlHelper.RadioButtonFor(expression, value, htmlAttrs);
}
}<span style="font-size: 9pt;"> </span>
You can also have another overload accepting html attributes from your view :-
public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object value, object htmlAttributes, string parentContainer)
{
var htmlAttrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
htmlAttrs.Add("radio-list", "true");
htmlAttrs.Add("radio-list-parent", parentContainer);
return htmlHelper.RadioButtonFor(expression, value, htmlAttrs);
}
This will add two custom html attributes to the radio button html rendered.
i) "radio-list" - This will be used by a custom js file (which I will explain later)
ii) "radio-list-parent" - This will contain the parent div name (which will be used in your view and the custom js file)
2. Custom Js file
jquery.mvc.radiolist.js - This will make sure that when you check a certain radio button in the MainDiv area all other radio buttons are unchecked.
$(document).ready(function () {
$(":radio[radio-list='true']").each(function () {
var mainDiv = $("#" + this.id).attr("radio-list-parent");
var element = $("#" + this.id)[0];
$("#" + this.id).click(function () {
if ($("#" + mainDiv).find(":radio")) {
if ($("#" + element.id).prop("checked")) {
$("#" + element.id).prop("value", "true");
$("#" + mainDiv).find(":radio").each(function () {
if (this.id != element.id) {
$("#" + this.id).prop("checked", false);
$("#" + this.id).prop("value", "false")
}
});
}
}
});
});
});
3. Changes in View:-
I am showing it in a view/partial view where there is a loop (i.e. it is a repeating control/view). But this utility can be used anywhere, you just need to make sure that these radio buttons are surrounded with a div. I have shown it in razor view engine but in the same way you can use it in ASP.NET views:-
[PS: make sure you put a using block for the namespace where you have written your custom html helper (RadioButtonListHelper), small thing but worth noting down :) ]
<div id="divMain">
@for (int counter = 0; counter < Model.Count; counter++)
{
@Html.RadioButtonListFor(model => model[counter].IsPreferred, "false", "divMain")
}
</div>
You can also add your custom html attributes before passing the parent div (as shown in the overload above). This will make sure all your radio buttons map back to their respective model properties once posted.
In above case the data type for IsPreferred as nullable bool (i.e. bool?)
I will post updates if I add some more overloads to this.