Cascading DropDownList In ASP.NET MVC

In this article, I explain how to populate items in DropDownList on the basis of another DropDownList value.

I am also using entity framework code first model to get the list of countries and its states.

  • Open Visual Studio 2010.

  • Create a new ASP.NET MVC 3 or 4 web application and named it as Cascading DropDown for this application.

  • Choose Razor as the View engine and click OK.

  • Add a Controller in your project and give name as HomeController.

  • Create a model class in the Model folder as shown below:

    Country:
    1. public class Country  
    2. {  
    3.    public int CountryID { getset; }  
    4.    public string Name { getset; }  
    5.   
    6.    public virtual ICollection<State> States { getset; }  
    7. }  
    State:
    1. public class State  
    2. {  
    3.    public int StateID { getset; }  
    4.    public string Name { getset; }  
    5.   
    6.    public int CountryID { getset; }  
    7.    public virtual Country Country { getset; }  
    8. }  
    ModelDbContext:
    1. public class ModelDbContext : DbContext  
    2. {  
    3.    public DbSet<Country> Countries { getset; }  
    4.    public DbSet<State> States { getset; }  
    5. }  

Model

In this model class I have created a property CountryID (hold selected value of country), State (hold selected value of state), Countries and States (hold list of available country and its states).

  1. public class Model  
  2. {  
  3.     public int ? CountryID  
  4.     {  
  5.         get;  
  6.         set;  
  7.     }  
  8.     public int ? StateID  
  9.     {  
  10.         get;  
  11.         set;  
  12.     }  
  13.     public IEnumerable < Country > Countries  
  14.     {  
  15.         get;  
  16.         set;  
  17.     }  
  18.     public IEnumerable < State > States  
  19.     {  
  20.         get;  
  21.         set;  
  22.     }  
  23. }  
Add some sample data in database and initialize it when database has been created:
  1. public class ModelInitializer: DropCreateDatabaseIfModelChanges < ModelDbContext >  
  2. {  
  3.     protected override void Seed(ModelDbContext context)  
  4.     {  
  5.         var countries = new List < Country >  
  6.         {  
  7.             new Country  
  8.             {  
  9.                 Name = "India"  
  10.             },  
  11.             new Country  
  12.             {  
  13.                 Name = "USA"  
  14.             },  
  15.             new Country  
  16.             {  
  17.                 Name = "South Africa"  
  18.             },  
  19.             new Country  
  20.             {  
  21.                 Name = "Australlia"  
  22.             },  
  23.         };  
  24.         var states = new List < State >  
  25.         {  
  26.             new State  
  27.             {  
  28.                 Name = "Delhi", Country = countries.Single(m => m.Name == "India")  
  29.             },  
  30.             new State  
  31.             {  
  32.                 Name = "Mumbai", Country = countries.Single(m => m.Name == "India")  
  33.             },  
  34.             new State  
  35.             {  
  36.                 Name = "California", Country = countries.Single(m => m.Name == "USA")  
  37.             },  
  38.             new State  
  39.             {  
  40.                 Name = "Newyork", Country = countries.Single(m => m.Name == "USA")  
  41.             },  
  42.             new State  
  43.             {  
  44.                 Name = "Capetown", Country = countries.Single(m => m.Name == "South Africa")  
  45.             },  
  46.             new State  
  47.             {  
  48.                 Name = "Bolavia", Country = countries.Single(m => m.Name == "South Africa")  
  49.             },  
  50.             new State  
  51.             {  
  52.                 Name = "Sydney", Country = countries.Single(m => m.Name == "Australlia")  
  53.             },  
  54.             new State  
  55.             {  
  56.                 Name = "Melbourne", Country = countries.Single(m => m.Name == "Australlia")  
  57.             },  
  58.         };  
  59.         countries.ForEach(m => context.Countries.Add(m));  
  60.         states.ForEach(m => context.States.Add(m));  
  61.     }  
  62. }  
Add a connection string in the web.config file under the configuration tag:
  1. <connectionStrings>  
  2.    <add name="ModelDbContext" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CountryDb; Integrated Security=true;" providerName="System.Data.SqlClient"/>  
  3. </connectionStrings>  
Modify the Global.asax file as shown below:
  1. protected void Application_Start()  
  2. {  
  3.     Database.SetInitializer(new CascadingDropDown.Models.ModelInitializer());  
  4.     AreaRegistration.RegisterAllAreas();  
  5.     WebApiConfig.Register(GlobalConfiguration.Configuration);  
  6.     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  
  7.     RouteConfig.RegisterRoutes(RouteTable.Routes);  
  8. }  
Create a HomeController and add the following action methods. In this controller, Index action returns a Model type object to Index view by holding the list of countries from the database. SelectCountry action returns a list of states  on the basis of country id.
  1. ModelDbContext db = new ModelDbContext();  
  2. public ActionResult Index()  
  3. {  
  4.     Model model = new Model  
  5.     {  
  6.         Countries = db.Countries.ToList()  
  7.     };  
  8.     return View(model);  
  9. }  
  10. [HttpPost]  
  11. public virtual ActionResult SelectCountry(int ? countryid)  
  12. {  
  13.     var states = countryid.HasValue ? db.Countries.FirstOrDefault(m => m.CountryID == countryid).States : null;  
  14.     Model model = new Model  
  15.     {  
  16.         CountryID = countryid,  
  17.             Countries = db.Countries.ToList(),  
  18.             States = states  
  19.     };  
  20.     if (Request.IsAjaxRequest()) return PartialView("_States", model);  
  21.     else return View("Index", model);  
  22. }  
Add an Index View and modify this as given below:
  1. @model CascadingDropDown.Models.Model  
  2. @{  
  3.     Layout = null;  
  4. }  
  5.   
  6. <!DOCTYPE html>  
  7. <html>  
  8.     <head>  
  9.         <meta name="viewport" content="width=device-width" />  
  10.         <title>Index</title>  
  11.         <script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"></script>  
  12.         <script type="text/javascript">  
  13.             $(document).ready(function () {  
  14.   
  15.                 $('input[type=submit]').hide();  
  16.   
  17.                 $('#CountryID').change(function () {  
  18.                     $(this).parents('form').submit();  
  19.                     return false;  
  20.                 });  
  21.   
  22.                 $("form[action$='SelectCountry']").submit(function () {  
  23.   
  24.                     $.ajax({  
  25.                         url: $(this).attr('action'),  
  26.                         type: 'post',  
  27.                         data: $(this).serialize(),  
  28.                         success: function (response) {  
  29.                             $('#states').html(response);  
  30.                         }  
  31.                     });  
  32.                     return false;  
  33.                 });  
  34.             });  
  35.         </script>  
  36.     </head>  
  37.     <body>  
  38.         <div>  
  39.             @using (Html.BeginForm("SelectCountry""Home"))  
  40.             {  
  41.   
  42.                 <fieldset>  
  43.                     <legend>Countries</legend>  
  44.                     @Html.DropDownListFor(m => m.CountryID, new SelectList(Model.Countries,"CountryID""Name"), "[Please select a Country]")  
  45.   
  46.                     <input type="submit" value="Select" />  
  47.                 </fieldset>  
  48.             }  
  49.   
  50.         </div>  
  51.         <div id="states">  
  52.             @Html.Partial("_States", Model)  
  53.         </div>  
  54.     </body>  
  55. </html>  
Add a _States partial view:
  1. @model CascadingDropDown.Models.Model  
  2. <fieldset>  
  3.    @if (Model.States != null && Model.States.Count() > 0)  
  4.    {  
  5.       <legend>States</legend>  
  6.       @Html.HiddenFor(m => m.CountryID);  
  7.       @Html.DropDownListFor(m => m.StateID, new SelectList(Model.States, "StateID","Name"), "[Please select a state]")  
  8.    }  
  9.    else  
  10.    {  
  11.       <legend>No states available</legend>  
  12.    }  
  13. </fieldset>  

 

Now run an application. It will something look like below:

Run Application

When JavaScript is turned off a select button will also be displayed in the UI in order to populate the states.

Country

When you select the country, it will populate all states in the state DropDown on the basis of selected country. You can see in the following screenshot.

Select country

Thanks for reading this article. You can enter your valuable comments and suggestion to improve this article in the comment box.

Read more articles on ASP.NET: