Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Javascript

Knockout that Cascading dropdown

4.50/5 (7 votes)
9 Mar 2012CPOL1 min read 44.2K  
How you can make cascading dropdowns with Knockout. Knockout is a JavaScript library which provides you some stuff to implement the MVVM pattern.

In this article, I will explain how you can make cascading dropdowns with Knockout. Knockout is a JavaScript library which provides you some stuff to implement the MVVM pattern. Knockout provides you the following stuff:

  • Declarative bindings: Easily associate DOM elements with model data using a concise, readable syntax
  • Automatic UI Refresh: When your data model’s state changes, your UI updates automatically
  • Dependency tracking: Implicitly set up chains of relationships between model data, to transform and combine it
  • Templating: Quickly generate sophisticated, nested UIs as a function of your model data

In the example below, I use jQuery to get some JSON server data.

HTML
<!DOCTYPE html>
<html>
    <head>
        <title>Knockout js cascading dropdown example</title>
        <script src="jquery-1.6.3.min.js" type="text/javascript"></script>
        <script src="knockout-1.2.1.js" type="text/javascript"></script>
        <script>
        var viewModel = {
            country: ko.observable(),
            countries: ko.observableArray(),
            state: ko.observable(),
            states: ko.observableArray(),
            city: ko.observable(),
            cities: ko.observableArray(),
            result: ko.observable()
        };
        viewModel.countrySelect = ko.dependentObservable({
            read: viewModel.country,
            write: function (country) {
                this.country(country);
                $.getJSON('http://localhost:56502/KnockoutJS/CascadingDropdown/States/' + 
                          country.value, null, function (response) {
                    viewModel.states(response);
                });
            },
            owner: viewModel
        });
        viewModel.stateSelect = ko.dependentObservable({
            read: viewModel.state,
            write: function (state) {
                this.state(state);
                $.getJSON('http://localhost:56502/KnockoutJS/CascadingDropdown/Cities/' + 
                          state.value, null, function (response) {
                    viewModel.cities(response);
                });
            },
            owner: viewModel
        });
        viewModel.result = ko.dependentObservable(function () {
            var result = '';
            result += this.country() != undefined ? 'Country: ' + this.country().text + ', ' : '';
            result += this.state() != undefined ? 'State: ' + this.state().text + ', ' : '';
            result += this.city() != undefined ? 'City: ' + this.city().text : '';
            return result;
        }, viewModel);

        $(function () {
            $.getJSON('http://localhost:56502/KnockoutJS/CascadingDropdown/Countries/', 
                      null, function (response) {
                viewModel.countries(response);
            });
            ko.applyBindings(viewModel);
        });
        </script>
    <head>
    <body>
        <h1>Knockout js cascading dropdown example</h1>
        <select data-bind="options: countries, optionsCaption: 'Choose country...', 
            optionsValue: function(item) { return item.value; }, 
            optionsText: function(item) { return item.text; }, value: countrySelect, 
            valueUpdate: 'change'" id="Country" name="Country"></select>
        <select data-bind="options: states, optionsCaption: 'Choose state...', 
            optionsValue: function(item) { return item.value; }, 
            optionsText: function(item) { return item.text; }, value: stateSelect, 
            valueUpdate: 'change'" id="State" name="State"></select>
        <select data-bind="options: cities, optionsCaption: 'Choose city...', 
            optionsValue: function(item) { return item.value; }, 
            optionsText: function(item) { return item.text; }, value: city, 
            valueUpdate: 'change'" id="State" name="City"></select>
        <span data-bind="text: result"></span>
    </body>
</html>

The JSON server data should be an array of objects containing a ‘value’ and ‘text’ property. As you can see, I use the HTML5' ‘data-bind attribute’ to map my view model to my UI elements.

For example, your ASP.NET MVC3 action could look like this:

C#
public JsonResult States(string country)
{
    var states = _countryRepository.GetStates(country)
        .Select(s => new {
            text = s.StateName,
            value = c.StateCode
        });
    return Json(states, JsonRequestBehavior = JsonRequestBehavior.AllowGet);
}

I wrote the examples in Notepad, so there could be some issues. However, if I did my job well, this should be all to let all the magic happen.

Didn’t this knock out a bunch of JavaScript code you would write normally?

If you like it, share it! If you don’t, share it!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)