30

我在这里找到了一个使用 KnockoutJS 创建包含 optgroup 的选择列表的示例。这很好用,但我想将下拉列表的值绑定到我自己的 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);

​</p>

4

3 回答 3

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>

示例:http: //jsfiddle.net/rniemeyer/aCS7D/

于 2012-06-25T13:17:51.323 回答
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>
于 2014-12-22T18:53:02.680 回答
0

如果您想完全控制标题、组和选项并使其与 select 元素上的值绑定一起工作,您必须确保在绑定 select 的值绑定之前绑定所有选项。否则,一旦添加了标题选项,值绑定将清空 selectedOption 可观察对象。

例如,您可以添加一个自定义valueAfterChildren绑定,它包装值绑定并确保首先绑定子项。请看下面的示例,在应用绑定之前,它在稍微简化的视图模型上预先选择了“选项 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>

于 2019-12-13T15:05:17.970 回答