« Greenhouse and Energy Reporting NGERS | Main | Manifesto for Agile Software Development »
Sunday
31May2009

ASP.NET MVC Cascading DropDownLists

Creating DropDownLists using WebForms is easy enough, for those who are venturing into the the world of MVC this may not be as straight forward.

I’ll be using the classic scenario of Cars and their related makes and models.

CarController.cs

public class CarFormViewModel
{
MakeModelRepository makeModelRepository =
    new MakeModelRepository();

private string _carMake = "";

public Car Car { get; private set; }
public SelectList CarMakes { get; private set; }
public SelectList CarModels { get; private set; }
public string CarMake
{
get { return _carMake; }
set { _carMake = value; }
}

// Constructor
public CarFormViewModel(Car car)
{
Car = car;
CarMakes = new SelectList(makeModelRepository.
        GetCarMakes(), "Value", "Text");

if (car.CarMakeModelId > 0)
CarMake = car.CarMakeModel.CarMake;

CarModels = new SelectList(makeModelRepository.
        GetCarModels(CarMake), "Value", "Text", Car.CarMakeModelId);
}
}

Something to be aware of is the use of valueSelected when defining your SelectList, make sure your view items e.g. DropDownList names match your database field names. I found the selected value was not being set correctly when editing a records.

CarForm.aspx

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl
<Vehicles.Controllers.CarFormViewModel>" %>

<script type="text/javascript">
$(function() {
$("#CarMake").change(function() {
var carMake = $("#CarMake > option:selected").attr("value");
var urlAction = "<%= Url.Action("FindCarModels", "Car") %>";
$.getJSON(urlAction, { carMake: carMake }, function(data) {
$("#CarMakeModelId").addItems(data);
});
});
});
</script>

<%= Html.ValidationSummary("Edit was unsuccessful. Please correct
the errors and try again.") %>
<%
using (Html.BeginForm())
{%>
<fieldset>
<
legend>Car</legend>
<
p>
<
label for="CarMake">
Make:</label>
<%= Html.DropDownList("CarMake", Model.CarMakes) %>
<%= Html.ValidationMessage("CarMake", "*") %>
</p>
<
p>
<
label for="CarMakeModelId">
Model:</label>
<%= Html.DropDownList("CarMakeModelId", Model.CarModels) %>
<%= Html.ValidationMessage("CarMakeModelId", "*") %>
</p>
<
p>
<
input type="submit" value="Save" />
</
p>
</
fieldset>
<% } %>
<div>
<%=Html.ActionLink("Back to List", "Index") %>
</div>

Make sure to change the inherits property to reference your new ViewModel. Note the use of the Url.Action helper, this little snippet helps you creates the correct path to your controller action without the use of those dots e.g. …/<controller>/<action>/

jHelper.js

Borrowed from Steve Michelotti.

$.fn.clearSelect = function() {
return this.each(function() {
if (this.tagName == 'SELECT')
this.options.length = 0;
});
}

$.fn.addItems = function(data) {
return this.clearSelect().each(function() {
if (this.tagName == 'SELECT') {
var dropdownList = this;
$.each(data, function(index, optionData) {
var option = new Option(optionData.Text,
                         optionData.Value);

if ($.browser.msie) {
dropdownList.add(option);
}
else {
dropdownList.add(option, null);
}
});
}
});
}

Little helper that clears and adds items to DropDownLists.

Something I found frustrating is when in debug mode a script reference would work find but when running using IIS the script would not load correctly. What you had to do was use those good old dots to get it loading correctly. My tip is to use the ResovleUrl helper.

<script src="<%= ResolveUrl("~/Scripts/jquery-1.3.1.js") %>" 
type="text/javascript"></script>

<
script src="<%= ResolveUrl("~/Scripts/jHelper.js") %>"
type="text/javascript"></script>

There are some workarounds I’ve seen that don’t break intellisense but look a bit messy. I figure I’ve lived without it for this long.

Here is the source code, if there is anything that is unclear or you have any questions feel free to email me.

PrintView Printer Friendly Version

EmailEmail Article to Friend

Reader Comments (3)

Thanks for posting the source.

June 1, 2009 | Unregistered Commentergkochanowsky

Big thanks.

August 5, 2009 | Unregistered CommenterMatt

I would like to thank you for the efforts you have made in writing this article. I mostly agree with you most of the point I have subscribed the feed and looking forward for the followup subscriptions

September 11, 2009 | Unregistered Commenterplumber paddington

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>