Development

ASP.net MVC and JQuery Cascading Dropdown list

Imagine that you have an E-Commerce site and you would like the user to drill down into the attributes of a product to help the user find exactly what they need. You display a dropdown list of product colors. Each time a user selects a new color, a dropdown list displaying products available in that color is populated. In this demo, I've created a small application demonstrating on how to use ASP.net MVC 1.0 framework and JQuery to complete the task.

ASP_net-MVC-and-JQuery-Dropdown-Cascading

Back to Top

Data Models

First, for demonstration purposes and easy download, I created two Model Data sources without the use of SQL. Colors and Products:

Models/Colors.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace JQueryJsonSelectDemo.Models
{
  public class Color
  {
    public string ColorName { get; set; }
    public string ColorCode { get; set; }
    public int ColorId { get; set; }

    public static IQueryable<Color> GetColorDataList()
    {
      return new List<Color>()   
      {  
         new Color { ColorName = "Blue", ColorCode = "BL", ColorId = 1},  
         new Color { ColorName = "Red", ColorCode = "RD", ColorId = 2},  
         new Color { ColorName = "Grey", ColorCode = "GY", ColorId = 3},  
         new Color { ColorName = "Black", ColorCode = "BK", ColorId = 4},  
         new Color { ColorName = "Green", ColorCode = "GN", ColorId = 5},  
         new Color { ColorName = "Olive", ColorCode = "OL", ColorId = 6},  
         new Color { ColorName = "Orange", ColorCode = "O", ColorId = 7},  
         new Color { ColorName = "Pink", ColorCode = "PK", ColorId = 8},  
         new Color { ColorName = "Violet", ColorCode = "V", ColorId = 9},  
         new Color { ColorName = "Yellow", ColorCode = "YW", ColorId = 10}  
      }
      .AsQueryable<Color>();
    }
  }
}

Models/Product.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace JQueryJsonSelectDemo.Models
{
  public class Product
  {
    public string ProductName { get; set; }
    public int ColorId { get; set; }
    public int ProductId { get; set; }

    public static IQueryable<Product> GetProductDataList()
    {
      return new List<Product>()   
      {  
         new Product { ProductName = "Cup", ColorId = 2, ProductId = 1},  
         new Product { ProductName = "MP3 Player", ColorId = 4, ProductId = 2},  
         new Product { ProductName = "52\" LCD TV", ColorId = 5, ProductId = 3},  
         new Product { ProductName = "Fork", ColorId = 6, ProductId = 4},  
         new Product { ProductName = "Spoon", ColorId = 10, ProductId = 5},  
         new Product { ProductName = "Shirt", ColorId = 6, ProductId = 6},  
         new Product { ProductName = "Pant", ColorId = 4, ProductId = 7},  
         new Product { ProductName = "Shoes", ColorId = 2, ProductId = 8},  
         new Product { ProductName = "Sun Glasses", ColorId = 1, ProductId = 9},  
         new Product { ProductName = "Pen", ColorId = 2, ProductId = 10}  
      }
      .AsQueryable<Product>();
    }
  }
}

Back to Top

The Controller

Next, I created a class (IndexFormViewModel) to pass the Colors as a SelectList Collection to the strongly-typed view. And also create an Action FindProductsByColorID that returns a JsonResult that will be used by the JQuery code in the view to populate the cascading dropdown list.

Controllers/HomeController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JQueryJsonSelectDemo.Models;

namespace JQueryJsonSelectDemo.Controllers
{

  public class IndexFormViewModel
  {

    // Properties
    public SelectList Colors { get; private set; }

    // Constructor
    public IndexFormViewModel()
    {
      var colors = from c in Color.GetColorDataList()
                   select c;
      Colors = new SelectList(colors, "ColorId", "ColorName");
    }
  }

  [HandleError]
  public class HomeController : Controller
  {
    public ActionResult Index()
    {
      ViewData["Message"] = "ASP.net MVC JQuery Cascading Select Demo!";
      return View(new IndexFormViewModel());
    }

    public ActionResult About()
    {
      return View();
    }

    public JsonResult FindProductsByColorID(int colorid)
    {
      // Simulate Loading Data "wait" 
      System.Threading.Thread.Sleep(1500);

      // return Json result using LINQ to SQL
      return new JsonResult
      {
        Data = (from p in Product.GetProductDataList()
                where p.ColorId == colorid
                select p).ToArray<Product>()
      };
    }
  }
}

Back to Top

Routing for the Ajax to call.

I create a route that I can call using the JQuery Ajax code.

Global.asax

      routes.MapRoute(
          "FindProducts",
          "FindProducts/{colorid}",
          new { controller = "Home", action = "FindProductsByColorID", colorid = "" }
      );

Back to Top

The View

Finally, The view which contains the JQuery code to make an Ajax request to my Home Controller Action (FindProductsByColorID) which returns a Json Result. If data is returned from the Action, the Products dropdown will be removed from being disabled and the options will be populated by the array from the JsonResult.

Views/Home/Index.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<JQueryJsonSelectDemo.Controllers.IndexFormViewModel>" %>
<%@ Import Namespace="JQueryJsonSelectDemo.Models" %>

<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">Home Page</asp:Content>
<asp:Content ID="Head" ContentPlaceHolderID="HeadContent" runat="server">
<script type="text/javascript">
  $(function() {
    $("select#Colors").change(function() {
      var color = $("#Colors > option:selected").attr("value");

      $.ajax({
        type: "GET",
        contentType: "application/json; charset=utf-8",
        url: "FindProducts/" + color,
        data: "{}",
        dataType: "json",
        success: function(data) {
          $('#ProductsDiv > div').remove(); // remove any existing Products
          if (data.length > 0) {
            var options = '';
            for (p in data) {
              var product = data[p];
              options += "<option value='" + product.ProductId + "'>" + product.ProductName + "</option>";
            }
            $("#Products").removeAttr('disabled').html(options);

          } else {
            $("#Products").attr('disabled', true).html('');
            $("#ProductsDiv").append('<div>(None Found)</div>');
          }
        }
      });
    });
  });
</script>

</asp:Content>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
  <h2><%= Html.Encode(ViewData["Message"]) %></h2>
  
  <p>
    <label class="formlabel" for="Colors">Colors:</label>
    <%=Html.DropDownList("Colors", Model.Colors)%>
  </p>
  <p>
    <div id="ProductsDiv"></div>
  </p>
  <p>
    <label class="formlabel" for="Products">Products:</label>
    <select id="Products" disabled></select>
  </p>
</asp:Content>

 

 

Sharing is caring.
  • Subscribe to Post Comment Feed
  • Share this post on Delicious
  • StumbleUpon this post
  • Share this post on Digg
  • Tweet about this post
  • Share this post on Mixx
  • Share this post on Technorati
  • Share this post on Facebook
  • Share this post on NewsVine
  • Share this post on Reddit
  • Share this post on Google
  • Share this post on LinkedIn

Comments

11 responses to "ASP.net MVC and JQuery Cascading Dropdown list"

  • yazılım says:

    Nice article. I was looking for a solution like this, there are a couple of examples out there but with your article its more clear to me how to use it. Thanks for sharing

  • Roslyn Roslyn says:

    Is it possible to set the cascading drop down box to a value in a database? For example, on an edit page?

  • aDaNG aDaNG says:

    Hello, it's a good example. But I still have a question,
    how can I post data(products) in the second dropdownlist?
    I cannot get the data like this
    string s = Request.Form["Colors"].ToString();
    what can I do?

    • tinamou tinamou says:

      @aDaNG
      1. change <select id="Products" disabled></select> to <select id="Products" name="Products" disabled></select>
      2. add form to Views/Home/Index.aspx
      <% using (Html.BeginForm()) { %>
      // form content (drop downs etc.)
      <input type="submit" value="post"/>
      <% } %>
      3. add to Controllers/HomeController.cs
      [AcceptedVerbs(HttpVerbs.Post)]
      public ActionResult Index(string Colors, string Products)
      {
      // smth to do with colors and products
      return View();
      }

      Of course it will post value from selected option in this case ColorId and ProductId

  • Raman Raman says:

    Just what I was looking for -- succint and to the point. Thanks.

  • Starboy Starboy says:

    Thanks for this article. Simple and to the point.

  • Raman Raman says:

    Hi Michael,

    I've playing with the code and ran into a couple of issues.

    1. I had to change the url to start with a / as in "/FindProducts/" instead of "FindProducts/"

    2. I had to convert the "data," which is in JSON format, to a Javascript object using eval or JSN.parse.

    After having worked through these issues,  I'm running into the following problems on post-back.

    1. I cannot get the selected values for the drop-downs in the controller

    2. I cannot get the drop-down to select previously selected value after a post-back

    Any pointers on these would be much appreciated.

    Thanks,
    Raman

  • This is a pretty interesting idea. Seems to be working pretty well, other than the back button problem other commenters have mentioned. If I figure it out, will post the solution. Thanks for this. Cheers

  • John Marsing John Marsing says:

    You don't perchance have a version of this in VB.Net do you?  I've tried to convert it, but no luck.

    Thanks,
    John Marsing

  • femi femi says:

    Excellent! I wanted to implement something like this, thanks for your help.

Comments are closed