ASP.NET MVC–Cascading Dropdown Lists Tutorial


Part 1 – Defining the problem and the context

Problem

  • You want to cascade two or more dropdown lists from your view:
    • You want to fill the contents of the next dropdown based on the selection in the current dropdown list.
    • You want to display a list/table filtered based on the selection of the last dropdown list.

Context

There are several ways to achieve this, but before drilling into each of them let’s define the context:

Let’s say we want to display a list of continents and when we select a continent another list will be filled with countries from that continent. When we select a country we will show a table with information about cities from that particular country. Something like this:

For this we will use the following model:

Setup

Before going further let’s prepare the programming environment a little. What we need:

  1. Visual Studio 2010 with Service Pack 1 (the edition doesn’t matter):
  2. ASP.NET MVC 3 Tools Update (and of course ASP.NET MVC 3 RTM):
    • You can install it via Web PI or download it from here . Also you can read about it here
  3. NuGet 1.3:
    • The 1.2 version will be installed by the MVC 3 Tools Update. You can upgrade it from Visual Studio Extension Manager or from here
  4. NuGet packages relevant for this tutorial (some of them are installed when you create a new ASP.NET MVC3 project and can be updated):
    • EntityFramework.4.1.10331.0 (pre-installed)
    • jQuery.1.6.1 (pre-installed as version 1.5.1 and can be updated from NuGet)
    • T4MVC (version at the time of writing 2.6.54)
    • SqlServerCompact.(version at the time of writing 4.0.8482.1)
    • EntityFramework.SqlServerCompact (version at the time of writing 4.1.8482.2)
    • MvcScaffolding.(version at the time of writing 1.0.0) – this must be installed from the NuGet Package Manager Console (Tools\Library Package Manager) by running the command Install-Package MvcScaffolding

We will use SQL Compact 4.0 to hold the data for this sample and we will access the data using EntityFramework 4.1 and the repository pattern. Lucky for us there is the MvcScaffolding package that will generate pretty much everything. In order to do that we need to run the following commands at the NuGet Package Manager Console (Tools\Library Package Manager) :

  1. Scaffold Repository Continent -Area:CascadingDropDownLists
  2. Scaffold Repository CascadingDropDownLists.Models.Country -Area:CascadingDropDownLists
  3. Scaffold Repository CascadingDropDownLists.Models.City -Area:CascadingDropDownLists

    The –Area parameter is optional. If you don’t have an area you can delete it.

    The result of running the above commands will be 4 files:

    1. ContinentRepository.cs
    2. CountryRepository.cs
    3. CityRepository.cs
    4. AtlasContext.cs

Because we will only display data from the database we need to have some seed data. For this we need to create a Database Initializer as follows (see the whole class in the source code download):

    public class AtlasContextInitializer : DropCreateDatabaseIfModelChanges<AtlasContext>
    {
        protected override void Seed( AtlasContext context )
        {
            //Add continents
            var europe = new Continent { Name = "Europe" };
            var oceania = new Continent { Name = "Oceania" };
            //Add countries
            //Europe
            europe.Countries = new Collection<Country>
            {
                new Country{Name = "Russia", Population = 142200000}, 
                new Country{Name = "Germany", Population = 83251851}
            };
            var romania = new Country { Name = "Romania" , Population = 21698181 };
            europe.Countries.Add( romania );

            //Add cities
            romania.Cities = new Collection<City>
            {
                new City {Name = "Bucharest", Population = 1926334}
            };
            //Add to context
            context.Continents.Add( europe );
            context.Continents.Add( oceania );
            context.SaveChanges( );
        }
    }

In order to enable de initializer we need to add the following line in the Application_Start handler in Global.asax.cs:

System.Data.Entity.Database.SetInitializer( new AtlasContextInitializer( ) );

The database will be created when we first try to read something from it. But this is the job of the next post.

I won’t go into further details about EntityFramework 4.1 and the Repository pattern because we will move away from the scope of this post. If you want to learn more please see the links from the References section.

What we have at this moment:

  1. Project setup with NuGet Packages
  2. Model to work with
  3. Database with seed data

We will define next a view model called Atlas that will help in the next parts:

public class Atlas
{
    public int? SelectedContinentId { get; set; }
    public int? SelectedCountryId { get; set; }
    public IEnumerable<Continent> Continents { get; set; }
    public IEnumerable<Country> Countries { get; set; }
    public IEnumerable<City> Cities { get; set; }
}

In each of the following parts we will create separate controllers, views and partial views even some of the code can be reused. This will help to see the differences from each method used to cascade the dropdown lists.

References

EntityFramework 4.1 | Repository Pattern | MvcScaffolding

Download

Download code

 

14 Comments

  • @Antoine: I use http://studiostyl.es/schemes/son-of-obsidian

  • Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.

    The request for 'Home' has found the following matching controllers:
    Mvc3.Extensions.Demo.Areas.CascadingDropDownLists.Controllers.HomeController
    Mvc3.Extensions.Demo.Controllers.HomeController
    I'm confused to which home controller should be called in the global asax.cs file! Could you please elaborate on this and what the correct namespace should be used.
    Thanks

  • @Dale: Add a strin[] parameter to the Default route in the Global.asax.cs like this new string[]{"Mvc3.Extensions.Demo.Areas.CascadingDropDownLists.Controllers.HomeController"}. In this way when you run the application the Home controller in the root area will be used as the default controller

  • I would give a try creating a TreeView with jQuery

  • @Tushar: http://weblogs.asp.net/raduenuca/archive/2011/04/24/asp-net-mvc-displaying-a-tree-view-using-a-recursive-declarative-helper-and-jquery.aspx

  • For me Seed is not getting fired...am I missing something to set it up?

  • @Jignesh: make sure you have this line in Global.asax.cs, Application_Start:
    System.Data.Entity.Database.SetInitializer( new AtlasContextInitializer( ) );

  • Thanks Radu, it is working the issue was with my coding not with .SetInitializer

  • hi, first of all thanks for your work
    second, i want to use repository pattern with existing database(mysql)
    than i want to save selected dropdown values to db.
    can u recommend any idea where to begin?
    thank in advance

  • AFTER selecting the second drop-down there should display one editable text field and total data information should be save in Url in XML.. I have a one requirement like this . can any one help me out for this.

  • this tutorial leaves a lot of holes and is not very explicit. All I really want to know how to do in MVC2 is populate the dropdown and when a selected value is selected, I want it to do something. This was an easy task in ASP.Net, and I really don't care about all the other tools you have listed. I would rather the tutorial just be to the point.

  • @tmathews: The purpose of this tutorial is to show several ways of cascading dropdownlists. What you want is included (the tutorial is for MVC3 with Razor and not MVC2 so you'll have to translate).
    Moving from ASP.NET to MVC can be frustrating but reading a book about MVC2/3 will clear that.

  • Common sense tells us to value time. MVC appears to be all about wasting time, doing less with more time, writing more code, in more files, typing more, etc. Somehow many programmers believe that the more complex something looks, the better it is. Common sense tells us otherwise. Layers upon layers of abstraction, unnecessary classes, 'getting high' on cryptic named so called design patterns - all to achieve very simple results. It all seems so useless.

  • @mike you're both right and wrong at the same time. The shortest road is the one you know (and I'll add like). For me ASP.NET MVC is the best thing that happened to the .NET world regarding web programming but this is what I think. Can you suggest a better way to do web programming in .NET?


Comments have been disabled for this content.