Посмотрите этот jsfiddle
Я встречаю два вопроса:
В частности, это:
<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/>
возвращает [объект Object] на экран. Если я изменяю последнюю строку для span data-bind="text: selectedMake.text"
она ничего не возвращает. Однако, если я использую subscribe
от нокаута и журнал на консоль, я могу вернуть object.text в порядке?
Вторая проблема заключается в том, что я select2: { }
первый тег select, добавляя select2: { }
в свой атрибут привязки данных. Это правильно изменит выпадающий список на стиль select2, но все каскадные свойства разваливаются.
Любая помощь или руководство будут с благодарностью оценены.
selectedMake является наблюдаемым, его значение будет каскадным экземпляром Option. Чтобы использовать это в своем диапазоне: текстовое связывание, вам понадобятся:
<span data-bind="text: selectedMake().text"></span>
Он работает, когда вы используете подписку, потому что получаете значение наблюдаемого.
Select2 пытается синхронизировать элемент select с его внутренним состоянием. К сожалению, он зависит от каждой опции, имеющей значение Id. Поскольку вы не используете привязки optionsValue, это не сработает. Я также использую select2, но я изменил их код, чтобы использовать optionIndex вместо Id и довольно сложную привязку select2 для управления различиями, например Ajax и multiselect.
Тем не менее, вы получаете образец, который работает с select2...
Я обновил JSFiddle, но различия ниже. В этом случае я создаю функцию-оболочку для создания пары наблюдаемых /id с подписями между 2. Связывание выбора имеет другое значение привязки значения и добавленную привязку optionValue Связывание диапазона имеет другое значение привязки текста.
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');
Рабочая скрипка: http://jsfiddle.net/jiggle/Lw2qJ/
Проблема 1:
Вы можете сделать span data-bind="text: selectedMake().text"
(обратите внимание на скобки), но только если selectedMake всегда будет иметь значение (и, следовательно, имеет свойство.text).
Есть несколько других способов сделать это, которые изложены на http://www.knockmeout.net/2011/08/simplifying-and-cleaning-up-views-in.html
Проблема 2:
Однако, когда я начал изучать проблему 2, я обнаружил, что свойство optionsValue должно быть установлено, чтобы select2 работал правильно (хотя кто-то мог поправить меня по этому поводу), поэтому я немного переработал так, чтобы ваш selectedMake больше не был объектом, а скорее свойство text и optionsValue: "text":
<select id="make" data-bind="select2:{} , options: carMakers, value: selectedMake,
optionsValue:'text',
optionsText : 'text', optionsCaption : 'Select your make'"></select><br/>
Это означает, что для ваших каскадных вычислений для следующих уровней вы должны изменить его, чтобы сначала просмотреть make из выбранного текстового значения make следующим образом:
viewModel.carTypes = ko.computed(function(){
if(viewModel.selectedMake()){
var make = ko.utils.arrayFirst(viewModel.carMakers,function(item){
console.log(item.text,viewModel.selectedMake());
return item.text===viewModel.selectedMake();
});
return make.childOptions;
}
});
Это также означает, что вы можете просто использовать Selected Make: <span data-bind="text: selectedMake"></span>
а не использовать скобки, поскольку вы не пытаетесь получить доступ к свойству наблюдаемого.
Вот снова скрипка: http://jsfiddle.net/jiggle/Lw2qJ/
Надеюсь, поможет.