Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strongly Typed RadioButtonlist

I want to get some options (say payment method cash, credit card etc.) and bind these to radio buttons. I believe there is no RadioButtonList in MVC 3.

Also, once radios are bound I want to show the previously selected option to the user while editing the answer.

like image 626
Vivek Avatar asked Apr 14 '11 08:04

Vivek


2 Answers

As always you start with a model:

public enum PaiementMethod
{
    Cash,
    CreditCard,
}

public class MyViewModel
{
    public PaiementMethod PaiementMethod { get; set; }
}

then a controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel();
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

and finally a view:

@model MyViewModel
@using (Html.BeginForm())
{
    <label for="paiement_cash">Cash</label>
    @Html.RadioButtonFor(x => x.PaiementMethod, "Cash", new { id = "paiement_cash" })

    <label for="paiement_cc">Credit card</label>
    @Html.RadioButtonFor(x => x.PaiementMethod, "CreditCard", new { id = "paiement_cc" })

    <input type="submit" value="OK" />
}

And if you want some more generic solution which encapsulates this in a helper you may find the following answer helpful.

like image 161
Darin Dimitrov Avatar answered Sep 18 '22 23:09

Darin Dimitrov


This is how I like to bind RadioButtonLists. The view model has a collection of my strongly typed objects. For example, maybe PaymentOptions is a code table. Along with the collection is a SelectedPaymentOptionKey (or Selected*Id if you prefix your primary keys with Id). Initially this key will just be default 0, but on postback, it will hold the value of the selected item.

public class PaymentSelectionVM
{
  public ICollection<PaymentOption> PaymentOptions { get; set; }
  public int SelectedPaymentOptionKey { get; set; }
}

public ViewResult PaymentSelection()
{
  var paymentOptions = db.PaymentOptions.ToList();
  return View(
    new PaymentSelectionVM { 
      PaymentOptions = paymentOptions,

      //This is not required, but shows how to default the selected radiobutton
      //Perhaps you have a relationship between a Customer and PaymentOption already,
      //SelectedPaymentOptionKey = someCustomer.LastPaymentOptionUsed.PaymentOptionKey
      //  or maybe just grab the first one(note this would NullReferenceException on empty collection)
      //SelectedPaymentOptionKey = paymentOptions.FirstOrDefault().PaymentOptionKey 
    });
} 

Then in the View:

@foreach (var opt in Model.PaymentOptions)
{          
  @*Any other HTML here that you want for displaying labels or styling*@
  @Html.RadioButtonFor(m => m.SelectedPaymentOptionKey, opt.PaymentOptionKey)
}

The m.SelectedPaymentOptionKey serves two purposes. First, it groups the Radio buttons together so that the selection is mutually exclusive(I would encourage you to use something like FireBug to inspect the generated html just for your own understanding. The wonderful thing about MVC is the generated HTML is fairly basic and standard so it shouldn't be hard for you to eventually be able to predict the behavior of your views. There is very little magic going on here.). Second, it will hold the value of the selected item on postback.

And finally in the post handler we have the SelectedPaymentOptionKey available:

[HttpPost]
public ActionResult PaymentSelection(PaymentSelectionVM vm)
{
   currentOrder.PaymentOption = db.PaymentOptions.Find(vm.SelectedPaymentOptionKey);
   ....
}

The advantage of this over using SelectListItems is you have access to more of the object's properties in the case that you are displaying a grid/table and need to display many values of the object. I also like that there are no hard coded strings being passed in the Html helpers as some other approaches have.

The disadvantage is you get radio buttons which all have the same ID, which is not really a good practice. This is easily fixed by changing to this:

  @Html.RadioButtonFor(m => m.SelectedPaymentOptionKey, opt.PaymentOptionKey, new { id = "PaymentOptions_" + opt.PaymentOptionKey})

Lastly, validation is a bit quirky with most all of the radio button techniques I've seen. If I really needed it, I would wire some jquery up to populate a hidden SelectedPaymentOptionsKey whenever the radio buttons are clicked, and place the [Required] or other validation on the hidden field.

Another workaround for the validation problem ASP.NET MVC 3 unobtrusive validation and radio buttons

This looks promising but I haven't had a chance to test it: http://memoriesdotnet.blogspot.com/2011/11/mvc-3-radiobuttonlist-including.html

like image 36
AaronLS Avatar answered Sep 17 '22 23:09

AaronLS