Pre-populating nested (cascading) dropdowns
https://groups.google.com/d/topic/knockoutjs/4bbUhl31gOY/discussion
by bizamajig
HTML
<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/knockout-latest.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);