Please see this jsfiddle
I am encountering two issues:
Specifically, this:
<select id="make" data-bind="options: carMakers,
value: selectedMake,
optionsText : 'text',
optionsCaption : 'Select your make'">
</select><br/>
Selected Make: <span data-bind="text: selectedMake"></span><br/>
returns [object Object] to the screen. If I alter the last line to span data-bind="text: selectedMake.text"
it returns nothing. However, if I use subscribe
from knockout and log to the console, I can return the object.text fine?
The second issue is when I alter the first select tag by adding select2: { }
to its data-bind attribute. This will properly change the dropdown to the select2 style, but all the cascading properties fall apart.
Any help or guidance would be greatly appreciated.
selectedMake is an observable, its value will be cascadingOption instance. To use this in your span:text binding you will need :
<span data-bind="text: selectedMake().text"></span>
It works when you use subscribe because you get the value of the observable.
Select2 tries to synchronise the select element with it's internal state. Unfortunately it relies on each option having an Id value. Because you don't use the optionsValue binding this will not work. I also use select2 but I have changed their code to use optionIndex instead of Id and a fairly complicated select2 binding to manage the differences, like Ajax, and multiselect.
However, you get your sample working with select2...
I have updated your JSFiddle but differences are below. In this I create a wrapper function to build an observable/id pair with subscriptions between the 2. The select binding has a different value binding value, and an added optionValue binding The span binding has a different text binding value.
HTML
<div>
<select id="make" data-bind="options: carMakers, value: selectedMake.id, optionsValue: 'text', optionsText : 'text', optionsCaption : 'Select your make', select2: {}"></select><br/>
Selected Make: <span data-bind="text: selectedMake().text"></span><br/>
<select id="type" data-bind="options: carTypes, value: selectedType.id, optionsValue: 'text', optionsText : 'text', optionsCaption : 'Select your type', enable : carTypes, select2: {}"></select><br/>
Selected Model: <span data-bind="text: selectedType().text"></span><br/>
<select id="model" data-bind="options: carModels, value: selectedModel.id, optionsValue: 'text', optionsText : 'text', optionsCaption : 'Select your Model', enable: carModels, select2: {}"></select><br/>
Selected Model: <span data-bind="text: selectedModel().text"></span><br/>
</div>
Javascript
var makeObservableForSelect2 = function( sourceOptions, idSelector ) {
var target = ko.observable({});
target.id = ko.observable();
target.id.subscribe( function(id) {
var realSource = ko.unwrap(sourceOptions)
if ( !realSource ) {
return;
};
// Don't set target if id already matches to stop infinite loop.
if ( target() && target()[idSelector] === id ) {
return;
}
target( realSource.filter( function(item) { return item[idSelector] === id; } )[0] || {} );
} );
target.subscribe( function(value) {
// Don't set id if id already matches to stop infinite loop.
if ( target.id() && value[idSelector] === target.id() ) {
return;
}
target.id(value[idSelector]);
});
return target;
};
var viewModel = {
carMakers: buildData()
};
viewModel.selectedMake = makeObservableForSelect2( viewModel.carMakers, 'text');
viewModel.carTypes = ko.computed(function(){
return viewModel.selectedMake() ? viewModel.selectedMake().childOptions : null;
});
viewModel.selectedType = makeObservableForSelect2( viewModel.carTypes, 'text');
viewModel.carModels = ko.computed(function(){
return viewModel.selectedType() ? viewModel.selectedType().childOptions : null;
});
viewModel.selectedModel = makeObservableForSelect2( viewModel.carModels, 'text');