如何将一个数组渲染成单选按钮列表?

10

我希望通过在Javascript中定义的数组循环并渲染一组单选按钮。我的代码目前无法工作,如下所示(也可以在jsfiddle上查看):

<div data-bind="foreach: options" >
    <div>
        <input type="radio" name="optionsGroup" data-bind="checked: selected" />
        <span data-bind="text: label"></span>
     </div>    
</div>
var optionsList = [
    {"value": "a","label": "apple"},
    {"value": "b","label": "banana"},
    {"value": "c","label": "carrot"}
];
function viewModel() {
    var self = this;
    self.options = optionsList;
    self.selected = ko.observable("a");
    self.selected.subscribe(function(newValue) {
        alert("new value is " + newValue);
    });
}
ko.applyBindings(new viewModel());

如果我的数组是HTML的一部分,那么它可以正常工作,可以参考这个(或jsfiddle):

<div>
    <input type="radio" name="optionsGroup" value="a" data-bind="checked: selected"     />Apple
</div>
<div>
    <input type="radio" name="optionsGroup" value="b" data-bind="checked: selected" />Banana
</div>
<div>
     <input type="radio" name="optionsGroup" value="c" data-bind="checked: selected" />Carrot
</div>
<div data-bind="text: selected">
</div>
function viewModel() {
    var self = this;
    self.selected = ko.observable("a");
    self.selected.subscribe(function(newValue) {
        alert("new value is " + newValue);
    });
}    
ko.applyBindings(new viewModel());

我通过在JavaScript中生成所有HTML并使用复选框使其正常工作,但是在使用foreach迭代器生成一组单选按钮时遇到了难题。

有人能否提供像我第一个例子一样的示例?


1
你肯定能想出一个更加有信息量的标题。 - Matt Ball
1
值得注意的是,在您的viewModel中不需要var self = this。 删除该行并将所有的self更改为this。作用域没有问题。 - ruffin
4个回答

17

这是一种实现方式。请注意,在checked绑定之前应该先使用attr绑定。

var optionsList = [
    {"value": "a", "label": "apple"},
    {"value": "b", "label": "banana"},
    {"value": "c", "label": "carrot"}
];

function viewModel() {
    this.options = optionsList;
    this.selected = ko.observable("a");
}

ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<h3>Fruits</h3>
<div data-bind="foreach: options" >
  <label>
    <input type="radio"
           name="optionsGroup" 
           data-bind="attr: {value: value}, checked: $root.selected" />
    <span data-bind="text: label"></span>
  </label>    
</div>

<h3>Selected value:</h3>
<pre data-bind="text: ko.toJSON($root.selected)"></pre>


5
我的问题在于 attr 绑定没有出现在 checked 之前。这很合理,但不是一开始就显而易见的。 - kamranicus
上面答案的 JSFiddle 示例(仅供娱乐)。 - ruffin
在最近的 Knockout 版本中,$root 已经变成了 $parent。 - Daniele Dellafiore

2

您的代码出现了以下错误:

信息:ReferenceError: selected 未定义;

绑定值:checked: selected

您在视图模型层级上定义了 selected,但是您正在 foreach 内部引用它,因此 Knockout.js 在选项层级上寻找它。

请更改为:

<div><input type="radio" name="optionsGroup" data-bind="checked: selected" />

to:

<div><input type="radio" name="optionsGroup" data-bind="checked: $root.selected" />

$root.selected会在视图模型层面查找selected属性。

这里是修改后的代码。

有关伪变量(如$root)的更多信息,请参见3.访问父绑定上下文


1
为了能够获得整个对象,最好使用checkedValue而不是attr:{value},像这样:
Fruits
<div data-bind="foreach: options" >
    <div><input type="radio" name="optionsGroup" data-bind="checkedValue: $data, checked: $root.selected" />
    <span data-bind="text: label"></span></div>    
</div>

0
你的代码是有效的。只需在你的 jsfiddle 中包含 knockout.js,并设置文档的 "onDomready"。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接