我找到了一个示例here来创建一个使用KnockoutJS的optgroups的选择列表。这工作正常,但我想将下拉列表的值绑定到我自己的javascript对象,然后访问该对象的特定属性:
<select data-bind="foreach: groups, value:selectedOption">
<optgroup data-bind="attr: {label: label}, foreach: children">
<option data-bind="text: label"></option>
</optgroup>
</select>
function Group(label, children) {
this.label = ko.observable(label);
this.children = ko.observableArray(children);
}
function Option(label, property) {
this.label = ko.observable(label);
this.someOtherProperty = ko.observable(property);
}
var viewModel = {
groups: ko.observableArray([
new Group("Group 1", [
new Option("Option 1", "A"),
new Option("Option 2", "B"),
new Option("Option 3", "C")
]),
new Group("Group 2", [
new Option("Option 4", "D"),
new Option("Option 5", "E"),
new Option("Option 6", "F")
])
]),
selectedOption: ko.observable(),
specialProperty: ko.computed(function(){
this.selectedOption().someOtherProperty();
})
};
ko.applyBindings(viewModel);
答案 0 :(得分:40)
这种情况的一个很好的选择是创建一个快速自定义绑定,让你的“手工制作”选项的行为与options
绑定创建的选项相同(将对象作为元数据附加) 。绑定可能看起来像:
ko.bindingHandlers.option = {
update: function(element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
ko.selectExtensions.writeValue(element, value);
}
};
您可以使用它:
<select data-bind="foreach: groups, value: selectedOption">
<optgroup data-bind="attr: {label: label}, foreach: children">
<option data-bind="text: label, option: $data"></option>
</optgroup>
</select>
答案 1 :(得分:10)
此版本带标题,如果您想要选择父项:
<select data-bind="value: selectedOption ">
<option data-bind="value:'', text:'Select'"></option>
<!-- ko foreach: groups -->
<optgroup data-bind="attr:{label: label}">
<option data-bind="value: $data, text:label"></option>
<!-- ko foreach: children -->
<option data-bind="value: $data, text:label"></option>
<!-- /ko -->
</optgroup>
<!-- /ko -->
</select>
答案 2 :(得分:0)
如果要完全控制标题,组和选项,并使其与select元素上的值绑定一起使用,则必须确保在绑定select的值绑定之前,所有选项都已绑定。否则,一旦添加了标题选项,值绑定将清空selectedOption观察值。
例如,您可以添加一个自定义valueAfterChildren
绑定,该绑定包装值绑定并确保children are bound first。看看下面的示例,该示例在应用绑定之前预先选择了稍微简化的viewmodel上的“选项5”:
ko.bindingHandlers['valueAfterChildren'] = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
ko.applyBindingsToDescendants(bindingContext, element);
ko.bindingHandlers['value'].init(element, valueAccessor, allBindings, viewModel, bindingContext);
return { controlsDescendantBindings: true };
},
value: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
ko.bindingHandlers['value'].update(element, valueAccessor, allBindings, viewModel, bindingContext);
}
}
var viewModel = {
groups: [
{
label: "Group 1",
children: [{ label: "Option 1" }, { label: "Option 2" }, { label: "Option 3" }]
}, {
label: "Group 2",
children: [{ label: "Option 4" }, { label: "Option 5" }, { label: "Option 6" }]
}
],
selectedOption: ko.observable()
};
viewModel.selectedOption.subscribe(function(newVal) {
console.log(`selected ${!!newVal ? newVal.label : 'empty option'}`);
});
viewModel.selectedOption(viewModel.groups[1].children[1]);
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select data-bind="valueAfterChildren: selectedOption">
<option value="">Select</option>
<!-- ko foreach: groups -->
<optgroup data-bind="attr: {label: label}, foreach: children">
<option data-bind="value: $data, text: label"></option>
</optgroup>
<!-- /ko -->
</select>