Loading...
Loading...
Marco Franssen

In this article, I'll show you how to build cascading country, state, and city dropdowns with Knockout.js. Knockout.js is a JavaScript library that helps you implement the MVVM pattern. It provides:
In the example below, I use jQuery to fetch json from the server.
<!DOCTYPE html>
<html>
<head>
<title>Knockout js cascading dropdown example</title>
<script src="jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="knockout-2.1.0.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.computed({
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.computed({
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.computed(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 data should be an array of objects containing value and text properties. As you can see, I use the html5 data-bind attribute to connect my view model to the UI elements.
For example, your ASP.NET MVC 3 action could look like this.
public JsonResult States(string country)
{
var states = _countryRepository.GetStates(country)
.Select(s => new {
text = s.StateName,
value = c.StateCode
});
return new JsonResult { Data = states, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}I wrote these examples in Notepad, so there could be some issues. If I've done my job well, though, this should be all you need to make the magic happen.
Didn't that knock out a bunch of JavaScript code you'd normally have to write?
If you like it, share it! If you don't, share it anyway!
Marco Franssen
Use jQuery events and a mediator to connect independent JavaScript modules, keeping a product dialog and grid separate while they communicate.
Marco Franssen
Try Windows 8 Developer Preview in VirtualBox with this walkthrough of hardware requirements, virtual machine settings, and the installation wizard.
Marco Franssen
How the order of FakeItEasy call configurations affected my CQRS domain tests when aggregate roots prepared the event store before an edit.
Marco Franssen
Lessons from applying DDD and CQRS in a Scrum project: bounded contexts, aggregate roots, domain services, guard methods, and command-based tests.