Dropdown Lists in MVC 3

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.

This entry was posted in Tips and Tricks and tagged , , . Bookmark the permalink.

15 Responses to Dropdown Lists in MVC 3

  1. Stu says:

    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?

  2. codeoverload says:

    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

  3. Sophonias Gurmu says:

    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.

  4. Pingback: Blue Ray Plus - Latest Technology News

  5. bacarden says:

    This was a very usefull blog. Works perfect, thanks 🙂

  6. Santhosh says:

    What does the SelectListItem class contains?

  7. Nikunj says:

    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.

    • codeoverload says:

      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();

  8. Goppa says:

    Cannot implicitly convert type ‘System.Collections.Generic.List’ to ‘System.Collections.Generic.List

    at
    model.CardTypeOptions = GetCardTypes(“MS”);

    Please Help Me

  9. accs says:

    Thank you, It was helpful..:)

  10. par says:

    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?

    • codeoverload says:

      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 } );
      }

  11. Rohin says:

    Excellent man…

Leave a reply to codeoverload Cancel reply