haki
haki

Reputation: 9759

Knockout.js - Creating a reusable cascading select

Is it possible to create a reusable cascading combo box from a dictionary object using KO ?

For example, this data

{'A' : { 'A1':11, 'A2':12} , 
 'B' : { 'B1':21, 'B2':22, 'B3':33}, 
 'C' : { 'C1':31}}

would produce two cascading boxes, the first with the options 'A,B,C'. the second would update according to the selection. The dict might change in height but the tree will always be balanced.

Is it possible to create the elements from within a custom binding ? can a custom binding contain other custom bindings and subscribe to them ? is custom binding even the right approach here ?

I would appreciate some guidance.

Upvotes: 0

Views: 111

Answers (1)

Dhana Krishnasamy
Dhana Krishnasamy

Reputation: 2176

Basically this is what I have done

  1. Create a predefined structure /class which knows if it has list of values or just a single value.
  2. On the view side show the dropdown if its list else just show the text.
  3. On the root vm nest the structure created in step one and create the dict.

Here is the VM

var optionVM = function (name,isList, v) {
    var self = this;
    self.name=ko.observable(name);
    if (isList) self.values = ko.observableArray(v);
    else self.value = ko.observable(v);
    self.isList = ko.observable(isList);
    self.selected = ko.observable();
}
var vm = function () {
    var self = this;
    var a1Vm = new optionVM('A1',true, [new optionVM('A11',false,111), new optionVM('A12',false,122)]);
    var aVm = new optionVM('A',true, [new optionVM('A2',false,'21'), a1Vm]);

    var d = new optionVM('Root',true, [aVm, new optionVM('B',false,'B1'),new optionVM('C',false,'C1')]);
    self.dict = ko.observable(d);

}

ko.applyBindings(new vm());

Here is the view

    <select data-bind='options:dict().values,optionsText:"name",value:dict().selected'>
</select>

<div data-bind="template: {name: 'template-detail', data: dict().selected}"></div>

<script type="text/html" id='template-detail'>
    <!-- ko if:$data.isList -->
    <span> List:</span>
    <select data-bind='options:values,optionsText:"name",value:selected'>
    </select>
        <div data-bind="template: {name: 'template-detail', data: selected}"></div>
    <!-- /ko -->
     <!-- ko ifnot:$data.isList -->
    Value:<span data-bind="text:value"></span>
     <!-- /ko -->

</script>

And here is the jsFiddle

Improvements:

  • You can use isArray to identify if its list in the optionVM.
  • Some of the observables can be replaced with simple values if they are not going to change (e.g:name)

Upvotes: 1

Related Questions