I’ve been lucky enough to work full-time with ASP.NET MVC 3 for the past couple of months, and I’ve completely fallen in love. It’s quite a change from WebForms, and it took a while to ‘click’ so I’m putting together a few examples both as a personal reference, but also to help anyone looking to take the leap from WebForms.
The first thing I struggled with was how to implement dropdown lists, so this post will walk through the steps required to make a simple form:
The first step is to build a model for the form. We need two properties for the dropdown, one to hold the list of options and the other for the ID of the selected option:
public class CreditCardModel { public List<SelectListItem> CardTypeOptions { get; set; } [Display(Name = "Card Type")] public string CardTypeID { get; set; } [Display(Name = "Card Number")] [Required(ErrorMessage = "Please provide your card number")] public string CardNumber { get; set; } }
The controller class requires two action methods, one to show the initial form (the GET request) and one to handle the form submission (the POST request):
public class CreditCardController : Controller { public ActionResult AddCard() { var model = new CreditCardModel(); // Populate the dropdown options model.CardTypeOptions = GetCardTypes("MS"); // Set the default to American Express return View(model); } [HttpPost] public ActionResult AddCard(CreditCardModel model) { // TODO - Handle the form submit // Populate the dropdown options model.CardTypeOptions = GetCardTypes("MS"); // Set the default to American Express return View(model); } // TODO - AddCardComplete goes here // TODO - GetCardTypes goes here }
I’ve hard-coded the dropdown values inside the controller to keep things simple:
private List<SelectListItem> GetCardTypes(string defaultValue) { List<SelectListItem> items = new List<SelectListItem>(); items.Add(new SelectListItem { Text = "American Express", Value = "AE", Selected = (defaultValue == "AE") }); items.Add(new SelectListItem { Text = "Mastercard", Value = "MS", Selected = (defaultValue == "MS") }); items.Add(new SelectListItem { Text = "Visa", Value = "VS", Selected = (defaultValue == "VS") }); return items; }
The view needs the ‘@model’ directive at the top to bind to the CreditCardModel. I’m using Razor as my view engine of choice – quite simply, it rocks! Note the use of ValidationSummary, any validation errors will automatically appear here:
@model Demo.Models.CreditCardModel @{ ViewBag.Title = "Add Card"; } <h2>Add Card</h2> @using (Html.BeginForm()) { @Html.ValidationSummary() <table> <tr> <td>@Html.LabelFor(x => x.CardTypeID)</td> <td>@Html.DropDownListFor(x => x.CardTypeID, Model.CardTypeOptions)</td> </tr> <tr> <td>@Html.LabelFor(x => x.CardNumber)</td> <td>@Html.EditorFor(x => x.CardNumber)</td> </tr> </table> <input type="submit" value="Add Card" /> }
Inside the AddCard POST action we need a check that the model is valid before we save the card details. This can be checked by calling ModelState.IsValid which is available to all action methods.
Something to watch out for – it’s a recommended practice to redirect the user to an action following a post. The reason for this is to prevent the user accidentally re-submitting the form by refreshing the page. This is done by returning a call to RedirectToAction(), passing in the action name.
if (ModelState.IsValid) { // TODO - Save the data to your database... // Prevent the user resubmitting the card by asking their // browser to request a different page using a GET request return RedirectToAction("addcardcomplete"); }
Create a new view called AddCardComplete:
@{ ViewBag.Title = "Add Card Complete"; } <h2>Add Card Complete</h2> <p>Your card has been added</p>
Create an action method for the view inside the controller:
public ActionResult AddCardComplete() { return View(); }
All done! The selected value of the dropdown will be automatically bound to the CardTypeID property of the CreditCardModel instance.
Thanks very much, excellent. Can you give a little hint on using the viewmodels, could I use colon inherit from main model, just for the views?
Hi Stu,
I’m a little confused by your question. Are you asking if your model can inherit from a base class? If so, then yes. The model can inherit from almost anything. I think the only restriction is that the base type must have a default constructor.
Kind regards
James
Thank You very much man…. I have been looking around the internet for the past two day trying to learn about the MVC 3 framework and none of the tutorials I looked at tried to explain the dropdown list as you did. I am used to java spring so i was having trouble referencing the data being submitted from dropdowns in the view. The key info in this tutorial for me is the view model and how its properties reference the the values of selected options on a view. This solved a big part of my problem. Thank You.
Pingback: Blue Ray Plus - Latest Technology News
This was a very usefull blog. Works perfect, thanks 🙂
What does the SelectListItem class contains?
The SelectListItem class is part of MVC (System.Web.Mvc) and contains three properties: Selected (bool), Text (string) and Value (string).
Hi,
Thanks for this blog. It helps me.
Now, I want to access selected value of field into my controller, so how can i access that? Can you please provide me suggestion.
The selected value is automatically stored in the model by MVC3, so in the controller’s POST action method you can do:
var selectedValue = model.CardTypeID;
To get the selected text, you’ll need to perform a lookup:
var selectedText = (from x in model.CardTypeOptions where x.Value == model.CardTypeID select x.Text).FirstOrDefault();
Cannot implicitly convert type ‘System.Collections.Generic.List’ to ‘System.Collections.Generic.List
at
model.CardTypeOptions = GetCardTypes(“MS”);
Please Help Me
I’d check that the return type of GetCardTypes() matches the CardTypeOptions property. They should both be “List<SelectListItem>”. If that doesn’t work, try posting an example of the code to http://www.stackoverflow.com and let me know the URL of your question.
Thank you, It was helpful..:)
Hi, what if I need to send the CardType options via Ajax to an action method
say,
public JsonResult(CreditCardModel data)
how should I do this?
Normally you wouldn’t send *all* the card types options back to the server because the server already has these – it provided them during the initial GET request. What I suspect you really want to do is send the *selected* card type back to the server. This can be done elegantly with jQuery:
function save() {
var selectedCard = $(“#CardTypeID option:selected”).text();
$.post(“/creditcard/addcard”, { CardTypeID: selectedCard } );
}
Excellent man…