Master-detail DropDown lists and Partial Views with jQuery Ajax in MVC

Making use of jQuery Ajax calls in ASP.NET MVC can boost application’s performance. This way, you can GET or POST partial pieces of data from or to application server, without the need to send or retrieve back the entire page. This post will show you how use jQuery to load and fill a DropDown list asynchronously, with data come from the server. More over, we will see how to GET and display a partial view using the ajax method. To see all these interesting and quite useful techniques we are going to build an MVC application where the user is supposed to search for laptops. When the page is loaded for the first time, a DropDown list (Master) will be filled asynchronously with some random Manufacturers, such as “DELL” or “APPLE”. Selecting one of these manufacturers will cause a new jQuery Ajax call to fill a second DropDown list (Detail) which is going to display the laptop series/categories for the respective Manufacturer. Finally, when the user picks a category from the second list, an ajax call will fetch a Partial View from the server, displaying all the available laptops according both to the selected Manufacturer and the category.
ajaxfill
I will be showing only the parts you need to know in order to support the above functionality rather than guiding you step by step. Feel free to download the entire solution from the link you will find at the bottom of the page. I have created an MVC application using the Internet Application template in Visual Studio 2012. First of all we need to create the Model for our data. For simplicity we won’t use data from database but some mock data retrieved from “generate” methods. Create a C# class named Manufacturer as follow.

public class Manufacturer
    {
        public string ManCode { get; set; }
        public string ManName { get; set; }

        public static IQueryable<Manufacturer> GetManufacturers()
        {
            return new List<Manufacturer>
            {
                new Manufacturer {
                    ManCode = "AC",
                    ManName = "ACER"
                },
                new Manufacturer {
                    ManCode = "AP",
                    ManName = "APPLE"
                },
                new Manufacturer {
                    ManCode = "DE",
                    ManName = "DELL"
                },
                new Manufacturer {
                    ManCode = "SN",
                    ManName = "SONY"
                }
            }.AsQueryable();
        }
    }

The ManCode property will be used as the Value property of a DropDown list while the ManName will be the displaying text. The GetManufacturers() static method generates some mock manufacturer objects.
In the same way create a Category class in the Models folder as follow.

public class Category
    {
        public string ManCode { get; set; }
        public int CategoryID { get; set; }
        public string CategoryName { get; set; }

        public static IQueryable<Category> GetCategories()
        {
            return new List<Category>
            {
                new Category {
                    ManCode = "AC",
                    CategoryID = 1,
                    CategoryName = "Aspire R"
                },
                new Category {
                    ManCode = "AC",
                    CategoryID = 2,
                    CategoryName = "Aspire V3"
                },
                new Category {
                    ManCode = "AC",
                    CategoryID = 3,
                    CategoryName = "Aspire E"
                },
                new Category {
                    ManCode = "AP",
                    CategoryID = 4,
                    CategoryName = "MacBook Air"
                },
                new Category {
                    ManCode = "AP",
                    CategoryID = 5,
                    CategoryName = "MacBook Pro"
                },
//code omitted - check download link at the bottom

The ManCode property of the Category class is the foreign key to the Manufacture’s respective property. Having these simple classes we can start building the controller. We can use the default HomeController VS generated for us. Remove all the code inside the controller, leaving only the Index() Action method.

public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    }

We need a method that returns in JSON format a SelectList object having all manufactures. Add the following method to the HomeController.

public ActionResult ManufacturerList()
        {
            var manufacturers = Manufacturer.GetManufacturers();

            if (HttpContext.Request.IsAjaxRequest())
            {
                return Json(new SelectList(manufacturers.ToArray(), "ManCode", "ManName"), JsonRequestBehavior.AllowGet);
            }

            return RedirectToAction("Index");
        }

Simple enough to understand, the action checks if the request is an AjaxRequest and if so returns in JSON format a SelectList filled with the manufactures. We need a similar method to return all the laptop categories (or series of products if you wish) according to the selected manufacturer. This methods requires the selected value from the master DropDown list, that is the “ManCode”.

public ActionResult CategoryList(string ID)
        {
            var categories = from c in Category.GetCategories()
                             where c.ManCode == ID
                             select c;
            if (HttpContext.Request.IsAjaxRequest())
            {
                return Json(new SelectList(categories.ToArray(),"CategoryID","CategoryName"),
                    JsonRequestBehavior.AllowGet);
            }

            return RedirectToAction("Index");
        }

It’s time to create the Index.cshtml page now. Change the default contents of this page to the following.

@{
    ViewBag.Title = "Home Page";
}

@using (Html.BeginForm("Index", "Home", FormMethod.Post,
    new
    {
        id = "OrderLaptopFormID"
    }))
{
    <fieldset>
        <legend>Make an order</legend>
        <div>
            <label for="Manufacturers">Manufacturer</label>
        </div>
        <select id="ManufacturersID" name="Manufacturers"></select>
        <div id="categoryDiv">
            <label for="Categories">Category</label>
            <select id="CategoryID" name="Categories"></select>
        </div>
        <div id="divLaptops"></div>
    </fieldset>
    <input type="submit" value="Return" id="SubmitID" />
}

<script src="@Url.Content("~/Scripts/jquery-1.8.2.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/GetManufacturer.js")"></script>
<script src="@Url.Content("~/Scripts/manufacturerCategory.js")"></script>

As you can see it’s a very simple layout. It consist from two select HTML elements that we are going to fill with jQuery Ajax calls to our previously created methods and a “divLaptops” div, that will display a partial View. Pay attention to the last three lines of the above code. We are going to use two javascript files to fill the select lists and of course we need the jQuery library too. Make sure you have the respective jQuery version on your Scrips folder and add two javascript files, named GetManufacturer and manufacturerCategory respectively. Let’s see the GetManufacturer script first.

$(document).ready(function () {
    var URL = 'home/ManufacturerList/';
    $.getJSON(URL, function (data) {
        var items = '<option value="">Select Manufacturer</option>';
        $.each(data, function (i, manufacturer) {
            items += "<option value='" + manufacturer.Value + "'>" + manufacturer.Text
            + "</option>";
        });
        $('#ManufacturersID').html(items);
    });
});

The most important part is remember to assign the manufacturer.Value of a manufacturer JSON object to the value property of the select’s option element and the manufacturer.Text property as the select element’s text property. If you want to understand this better here’s how “data” variable looks like in debug mode, after retrieved from server.
mvcajaxfill_01
At this moment if you run your application you should see at least the Master DropDown list filled with all manufacturers. Now let’s look the second javascript file, manufacturerCategory. First we need to ensure that this Detail list is hidden when the page loads. Then we need to bind the Change event of the Master DropDown list to an ajax call that will eventually fill our second list. Here’s the code.

$(document).ready(function () {
    $('#categoryDiv').hide();
    $('#divLaptops').hide();
    $('#SubmitID').hide();

    $('#ManufacturersID').change(function () {
        var URL = 'home/CategoryList/' + $('#ManufacturersID').val();
        $.getJSON(URL, function (data) {
            var items = '<option value="">Select Category</option>';
            $.each(data, function (i, category) {
                items += "<option value='" + category.Value + "'>" + category.Text + "</option>";
            });
            $('#CategoryID').html(items);
            $('#categoryDiv').show();
        });
    });
});

We also passed the “ManCode” property value from the Master select list. Notice that the ManufacturersID is the first’s select list ID so the $(‘#ManufacturersID’).val() will return it’s selected value. Now that we have both the manufacturer and the category selected, we would like to display some products based on this selection. First of all let’s add a new Model class named “Laptop” as follow.

public class Laptop
    {
        public string Category { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }

        public static IQueryable<Laptop> GetProducts() {
            return new List<Laptop>
            {
                new Laptop {
                    Category = "Aspire R",
                    Name = "R7-571-6858",
                    Price = 999m
                },
                new Laptop {
                    Category = "Aspire V3",
                    Name = "V3-772G-9460",
                    Price = 1299m
                },
//Code omitted - check the download link at the bottom

A laptop product belongs to a specific Category and has also a Name and a Price property. The GetProducts() method returns some mock laptop objects. We will use a Partial View to display a list of Laptop objects retrieved from server. Right click the Views/Home/ folder and add a new Partial View named GetLaptops. Paste the following code.

@model IEnumerable<CascadingDDL.Models.Laptop>

<table style="background-color:ghostwhite">
    <thead>
        <tr>
            <th>Name</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        @foreach(var item in Model)
        {
        <tr>
            <td>@item.Name</td>
            <td>$ @item.Price</td>
        </tr>
        }
    </tbody>
</table>

The Partial View expects an array of Laptop objects and creates a new row in a table for each Laptop. Create a new action method to the HomeController that will return this Partial View.

public PartialViewResult GetLaptops(string category)
        {
            var laptops = (from l in Laptop.GetProducts()
                           where l.Category == category
                           select l).AsEnumerable();
            return PartialView(laptops);
        }

This action checks the category value passed and returns a list of laptops that belong to this category. Notice that you have to pass the Laptop objects to the Partial View. We will call this action through a jQuery Ajax call when the user selects a category from the Detail DropDown list, so go and add the following highlighted code inside the manufacturerCategory javascript file.

$(document).ready(function () {
    $('#categoryDiv').hide();
    $('#divLaptops').hide();
    $('#SubmitID').hide();

    $('#ManufacturersID').change(function () {
        var URL = 'home/CategoryList/' + $('#ManufacturersID').val();
        $.getJSON(URL, function (data) {
            var items = '<option value="">Select Category</option>';
            $.each(data, function (i, category) {
                items += "<option value='" + category.Value + "'>" + category.Text + "</option>";
            });
            $('#CategoryID').html(items);
            $('#categoryDiv').show();
        });
    });

    $('#CategoryID').change(function () {
        var category = $('#CategoryID option:selected').text();
        var URL = 'home/GetLaptops?category=' + category;

        $.ajax({
            url: URL,
            contentType: 'application/html; charset=utf-8',
            type: 'GET',
            dataType: 'html'

        })
        .success(function (result) {
            $('#divLaptops').show();
            $('#divLaptops').html(result);
        })
        .error(function (xhr, status) {
            alert(status);
        })

        $('#SubmitID').show();
    });
});

If you build and run your application you should see the result in the GIF image at the start of this post. That’s it, we saw how to asynchronously fill Dropdown lists in MVC and how to render a Partial View through Ajax call. You can download the entire solution we built from here. I hope you enjoyed the post! Make sure you follow this blog to get notified for new posts.

Advertisements


Categories: ASP.NET

Tags: , , ,

5 replies

  1. why I change my controller and action name.it doesn’t work?why???

  2. Chris, I can’t download the source solution from dropbox. It 404’s.
    Do you have this uploaded some place else? maybe Git?
    Thank you.

Trackbacks

  1. Knockout.js with Web API : The perfect compination « chsakell's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Chara Plessa

The purpose of this blog is to broaden my education, promote experimentation and enhance my professional development. Albert Einstein once said that “If you can’t explain it simply, you don’t understand it well enough” and I strongly believe him!

chsakell's Blog

Anything around ASP.NET MVC,WEB API, WCF, Entity Framework & AngularJS

Kumikoro

A Front End Developer's Blog

Muhammad Hassan

Full Stack Developer | ASP.NET | MVC | WebAPI | Advanced Javascript | AngularJS | Angular2 | C# | ES6 | SQL | TypeScript | HTML5 | NodeJS, MS candidate @LUMS, Grad & EX-Adjunct Faculty @NUCES-FAST, seasonal blogger & open-source contributor. Seattle, WA.

Software Engineering

Web development

IEvangelist

.NET, ASP.NET, C#, MVC, TypeScript, AngularJS

leastprivilege.com

Dominick Baier on Identity & Access Control

Happy DotNetting

In Love with Technology

Knoldus

Knols of experience to your advantage

knowshnet

Search - Read - Request - Share

Rahul's space

Learn, Share and Grow with me !

Dhananjay Kumar

Developer Evangelist @Infragistics | MVP @Microsoft |

SQL Authority with Pinal Dave

SQL Server Performance Tuning Expert

Conficient Blog

Random bits of tech from @conficient

Code! Code! Code!

SOLID & KISS

Code Wala

Designing and coding

Microsoft Mentalist

A way to start with Microsoft Technologies

Tony Sneed's Blog

A glimpse into the lives of Tony & Zuzana Sneed

Sriramjithendra Nidumolu

Personal Notes of Sriramjithendra

%d bloggers like this: