Pre-populating nested (cascading) dropdowns
https://groups.google.com/d/topic/knockoutjs/4bbUhl31gOY/discussion
by Dale Howard
HTML
<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-2.2.1.debug.js"></script>
<script src="http://benalman.com/code/projects/jquery-bbq/jquery.ba-bbq.js"></script>
<table>
<tr>
<th>Name</th>
<th>ParentOption</th>
<th>ChildOption</th>
<th></th>
</tr>
<tbody data-bind="template: { name: 'itemsTmpl', foreach: items }"></tbody>
</table>
<button data-bind="click: addItem">Add Item</button>
<hr />
<div data-bind="text: ko.toJSON(viewModel.items)"></div>
<script id="itemsTmpl" type="text/html">
<tr > <td > <input data-bind = "value: name" /> </td>
<td>
<select data-bind="options: viewModel.parentOptions, optionsText: 'name', optionsCaption: 'choose...', optionsValue: 'name', value: parentOption" /> </td>
<td>
<select data-bind="visible: parentOption, options: childOptions, optionsText: 'name', optionsCaption: 'choose...', optionsValue: 'name', value: childOption" /> </td>
<td>
<button data-bind="click: function() { viewModel.removeItem($data); }">Delete</button > </td>
</tr >
</script>
CSS
th, td {
padding: 2px;
}
JavaScript
function Item(name, parentOption, childOption) {
this.name = ko.observable(name);
this.parentOption = ko.observable(parentOption);
this.childOption = ko.observable(childOption);
this.childOptions = ko.dependentObservable(function () {
var parent = ko.utils.arrayFirst(viewModel.parentOptions, function (option) {
return option.name === this.parentOption();
}, this);
return parent ? parent.childOptions : [];
}, this);
};
//if necessary, remove the childOptions dependentObservable for our JSON output
Item.prototype.toJSON = function () {
var copy = ko.toJS(this);
delete copy.childOptions;
return copy;
}
var viewModel = {
parentOptions: [{
name: "parentA",
childOptions: [{
name: "childA1"
}, {
name: "childA2"
}]
}, {
name: "parentB",
childOptions: [{
name: "childB1"
}, {
name: "childB2"
}]
}, {
name: "parentC",
childOptions: [{
name: "childC1"
}, {
name: "childC2"
}]
}],
items: ko.observableArray(),
addItem: function () {
this.items.push(new Item("new"));
},
removeItem: function (item) {
this.items.remove(item);
}
};
viewModel.items.push(new Item("test", "parentA", "childA2"));
viewModel.items.push(new Item("test2", "parentC", "childC2"));
ko.applyBindings(viewModel);