Knockout - Cascading Dropdown
by Doug Hill
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.min.css">
<div class="container-fluid">
<section class="heirarchy">
<div class="row">
<div class="col-xs-12">
<h3>Hierarchy Filters:</h3>
</div>
</div>
<div class="row">
<section class="hrFilter">
<div class="col-sm-1">
<div class="filterLabel form-group"><i class="fa fa-fw fa-sitemap"></i><span data-bind="text: hrCatLabel" data-helptip="filters-hierarchy" title="<i class="fa fa-fw fa-lg fa-th-sitemap"></i> Hierarchy Category"></span>
</div>
</div>
<div class="col-sm-4">
<div class="filterValue form-group">
<div data-bind="css: {'noentry': hrCatSelected() === undefined, 'entry': hrCatSelected() !== undefined }, toggle: hrCatEdit, filterAnimate: hrCatEdit()" class="filterText"><span data-bind="text: hrCatSelected() === undefined ? 'nothing selected' : hrCatSelected"></span>
</div>
<div class="filterInput">
<select name="hrCatSelect2" data-bind="options: hrCatValues, optionsValue: 'id', optionsText: 'text', optionsCaption: '', value: hrCatSelected, uniqueName: true, select2: {allowClear: false, placeholder: 'select hierarchy category'}" class="form-control input-sm"></select>
</div>
</div>
</div>
<div class="col-sm-1 col-sm-offset-1">
<div class="filterLabel form-group"><i class="fa fa-fw fa-sitemap"></i><span data-bind="text: hrItemLabel" data-helptip="filters-hierarchy" title="<i class="fa fa-fw fa-lg fa-th-sitemap"></i> Hierarchy Item"></span>
...
JavaScript
/*global ko, jQuery*/
ko.bindingHandlers.select2 = {
init: function (element, valueAccessor, allBindings) {
"use strict";
var obj = valueAccessor(),
lookupKey = allBindings.lookupKey,
$element = jQuery(element),
select2Options;
select2Options = allBindings.get('select2') || {};
$element.select2(select2Options);
if (lookupKey) {
var value = ko.utils.unwrapObservable(allBindings.value);
$element.select2('data', ko.utils.arrayFirst(obj.data.results, function (item) {
return item[lookupKey] === value;
}));
}
if (allBindings.value) { // FIX no initial values
allBindings.value.subscribe(function (v) {
$element.trigger('change');
});
}
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$element.select2('destroy');
});
},
update: function (element, valueAccessor, allBindings) {
"use strict";
var $element = jQuery(element),
value = ko.utils.unwrapObservable(allBindings.value || allBindings.selectedOptions);
if (value) {
$element.select2('val', value);
}
}
};
var hrOptionsJSON;
var BoxVM = {
hrCatLabel: ko.observable('Category'),
hrCatValues: ko.observable(),
hrCatSelected: ko.observable(),
hrCatEdit: ko.observable(false),
hrItemLabel: ko.observable('Options'),
hrItemValues: ko.observable(),
hrItemSelected: ko.observable(),
hrItemEdit: ko.observable(false)
};
jQuery.get({
url: '/echo/json/',
dataType: 'JSON',
success: function (response) {
hrOptionsJSON = response;
BoxVM.hrCatValues = hrOptionsJSON;
},
data: [{
"id": "Organization",
"text": "Organization",
"children": [{
"id": "Mobility Customer Service",
"text": "Mobility Customer Service"
...