WebMatrix - jQuery Cascading Dropdown Lists

4.64 (11 votes)

I have looked at cascading dropdown lists with WebMatrix previously, but the approach I featured demonstrated the use of jQuery Templates. At the time, the jQuery Templates project looked promising, but since then, the jQuery team have decided not to take them beyond beta stage. So the reason for this article is to illustrate a more "traditional" jQuery approach to managing cascading dropdown lists when developing ASP.NET Web Pages using WebMatrix.

The article makes use of the ubiquitous Northwind database (SQL Server CE 4.0 version) and initially presents the user with a dropdown containing a list of categories drawn from the database. Once the user has selected a category, a second dropdown list is populated with products within that category without the page being posted back to the server. The article will show how to use jQuery to achieve this, using either standard HTML select elements, or the Web Pages HTML helpers for forms.

The first code sample shows a Razor page that includes a standard HTML select element being populated by the categories extracted from the Northwind database:

@{
    var db = Database.Open("Northwind");
    var categories = db.Query("SELECT CategoryId, CategoryName FROM Categories ORDER BY CategoryName");
}
<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Cascading Dropdown Lists</title>
        <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    </head>
    <body>
        <div>
            <select id="categoryId" name="categoryId">
                <option value="">-- Select Category --</option>
            @foreach(var category in categories){
                <option value="@category.CategoryId">@category.CategoryName</option>
            }
            </select>
        </div>
        <div>
            <select id="productId">
                <option value="">-- Select Product --</option>
            </select>
        </div>
    </body>
</html>

A second select element is added to the form. This will display products from the chosen category. The next code sample shows the same thing using the Web Pages DropDownList helper instead of HTML elements:

@{
    var db = Database.Open("Northwind");
    var data = db.Query("SELECT CategoryId, CategoryName FROM Categories ORDER BY CategoryName");
    var categories = data.Select(item => new SelectListItem {
        Value = item.CategoryId.ToString(), 
        Text = item.CategoryName
    });
}

<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Cascading Dropdown Lists</title>
    </head>
    <body>
        <div>
            @Html.DropDownList("categoryId", "-- Select Category --", categories)
        </div>
        <div>
            @Html.DropDownList("productId", "-- Select Product --", Enumerable.Empty<SelectListItem>())
        </div>
    </body>
</html>

The data is transformed into a collection of SelectListItem objects once it has been obtained from the database. The second (products) dropdown list has an empty collection of SelectListItem objects assigned to it.

When a category has been selected, a filtered list of products needs to be obtained and made available to the second dropdown. Since jQuery is the engine that will be responsible for requesting that data, it makes sense to return it in a format that jQuery is comfortable working with - and that's JSON. Here is the complete GetProducts.cshtml file that is responsible for processing the request and returning the data:

@{
    Layout = null;
    var categoryId = UrlData[0].IsEmpty() ? 1 : UrlData[0].AsInt();  
    var db = Database.Open("Northwind");
    var sql = "SELECT ProductId, ProductName FROM Products WHERE CategoryId = @0 ORDER BY ProductName";
    var products = db.Query(sql, categoryId);
    Json.Write(products, Response.Output);
}

Since you are returning JSON, you must not allow other characters to be included in the response. For that reason, all the default markup has been removed from the file. Layout has been set to null at the top of the file. This acts to override any possibilty that a Layout page has been set in a PageStart file, or might be set in one in the future which would result in extra characters interferring with the generated JSON. In this particular example, I am expecting the CategoryID value to be available in UrlData. If there isn't one, I have decided to use 1 as a default value for demo purposes. Once the data has been extracted from the database, The Json helper is used to convert it into JSON and return it to the requester.

Finally, here is the client-side script that manages the process. It is exactly the same regardless whether you are using HTML elements or HTML helpers:

<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.1.min.js" type="text/javascript"></script>
<script>
    $(function () {
        var productsSelect = $('#productId');
        productsSelect.attr('disabled', true);
        $('#categoryId').change(function () {
            var categoryId = $(this).val();
            $.getJSON('/GetProducts/' + categoryId, function (products) {
                productsSelect.attr('disabled', false);
                productsSelect.empty();
                productsSelect.append(
                        $('<option/>')
                            .attr('value', '')
                            .text('-- Select Product --'));
                $.each(products, function (index, product) {
                    productsSelect.append(
                        $('<option/>')
                            .attr('value', product.ProductId)
                            .text(product.ProductName)
                    );
                });
            });
        });
    });
</script>

You need to include a reference to the jQuery library. I have linked to a CDN-hosted copy of jQuery. The script block initially identifies the dropdown list that the products will appear in, and disables it. Then an event handler is registered that executes when the selected value in the categories dropdown list is changed. The selected value (categoryId) is passed to a getJSON command that requests the GetProducts page. The categoryId value is added to the Url as UrlData. The callback function enables the dropdown list, then clears it of any existing option elements. Then it adds a default option ( -- Select Product -- ) and iterates the products returned in the JSON response and adds those to individual option elements.

A GitHub repo is available which includes a sample site featuring the HTML element approach.

 

You might also like...

Date Posted:
Last Updated:
Posted by:
Total Views to date: 24614

11 Comments

- Mauro Otoni

Very good article. I would like to see an example of how popular a JQGrid.
Thanks again

- marcelle

This was very helpful. But how do i save the value selected if it is inside a form

- Serhat Albayoglu

Thank you for providing the above. However when I tried the above code with MVC 4 + Razor, it fails from the start. The part
<div>
@Html.DropDownList("categoryId", "-- Select Category --", categories)
</div>
complains that it does not have a definition for DropDownList. I am new to MVC and just wondering if it is worthwhile to continue with the learning curve. These as you rightly stated could be done so simply with .NET ASP web pages as you describe here. But when it is MVC the easiest things can become so complicated and I still have to find a sample that works. Any suggestions ?

- Mike

@Serhat,

The MVC dropdownlist helper is not the same as the one featured here for Web Pages. Having said that, I have no idea why you are getting the error that you report. You should post more details in a question to forums.asp.net

- Chris

$.getJSON('/GetProducts/'....
Mike please, where did the GetProducts come from. I am new to JSON

- Mike

@Chris,

GetProducts is GetProducts.cshtml. The contents of the file are included in the article, and you can also have a look at it in the download. The getJSON method makes n AJAX request to the file.

- Rob7765

Thanks this worked and is easy. How do I access the selected value of products dropdown?

- jabb3rwoq

I must be stupid. I have spent the last 3 days trying to get your code to work. Anyway I'm going back to old asp...

- Mike

@jabb3rwoq

You should try posting a question to forums.asp.net. Someone may well spot your error in a few minutes.

- NickBoro

Hi Mike,

First, you are awesome, love your posts, have learned so much. On this cascading dropdown topic I'm getting HTTP Response Code 304 Not Modified and the getJSON is not successful so I get no data. I can see the valid data in the response body using F12 - Network as you mentioned. Googled a bunch and see a lot of info about setting cache:false, but this is not working for me. Any suggestions? Using Webmatrix and have code almost identical to your examples above.

- Mike

@NikcBoro

It's impossible to diagnose your issue without a lot more information. You should post a question to the ASP.NET forums or Stackoverflow and include the code you are using.

Recent Comments

Julian 26/09/2016 14:27
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Fantastic, many thanks Mike! Had got half way down this road before finding your article - saved...

Abolfazl Roshanzamir 14/09/2016 05:36
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Nice article. Thanke you so much ....

cyrus 02/09/2016 15:12
In response to ASP.NET Web Pages vNext or Razor Pages
I've got some news. As Damian stated in this link: https://github.com/aspnet/Mvc/issues/5208 “We...

Simon 01/09/2016 08:00
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Thanks Mike, nice post and exactly what I was looking for. Like you said, I think I'll opt to the...

dave 20/08/2016 14:57
In response to ASP.NET Web Pages vNext or Razor Pages
Do SimplemembershipProvider in viewpages is supported?...

Steven 18/08/2016 04:40
In response to Entity Framework Code First and Stored Procedures
Can you provide the directives (using statements) you're using for EF7 example?...

yousaid 17/08/2016 22:08
In response to ASP.NET Web Pages vNext or Razor Pages
Increasingly, learning a Microsoft tool is no longer worth the return on investment. Too many tools...

jared 12/08/2016 05:54
In response to ASP.NET Web Pages vNext or Razor Pages
hi mike, just for clarification, is viewpages something different from webpages? is webpages still...

Jocke 08/08/2016 20:37
In response to Loading ASP.NET Core MVC Views From A Database Or Other Location
Good post! If this was to be implemented in a CMS where users can change the view files, how would I...

cyrus 05/08/2016 19:49
In response to ASP.NET Web Pages vNext or Razor Pages
I think adding these features to webpages make it complicated. msft forget webpages goal so we move...