2012-02-06 82 views
2

我正在用Knockout.js构建一个简单的应用程序作为概念验证。由于我对Knockout非常陌生,因此这个问题中的代码可能远非完美并且表现出不好的做法,所以请随时告诉我是否属于这种情况!KnockoutJS选项与重复值绑定

我使用options结合产生select元素的内容:

<select data-bind="options: titles, optionsText: 'display', optionsValue: 'value'"> 
</select> 

视图模型看起来是这样的:

var ViewModel = function() { 
    this.titles = ko.observableArray([]); 
}; 

在DOM准备好我推一些值该可观察数组(每个值是对象字面值,表示“标题”,例如“Mr”,“Mrs”等):

var data = [ 
    { value: "Mr", display: "Default Value" }, 
    { value: "Miss", display: "Miss" }, 
    { value: "Mr", display: "Mr" }, 
    { value: "Ms", display: "Ms" } 
]; 
ko.applyBindings(view); 
for(var i = 0; i < data.length; i++) { 
    view.titles.push(data[i]); //Push titles into observable array 
} 

不要问为什么有两个对象的值为“Mr”,这就是我必须处理的数据的来源。我无法改变它。但是,这是导致问题的原因。我期望第一个对象代表选定的选项,但事实并非如此。第三个对象表示实际结束的option元素作为默认选择。

我相信这是由于可观察数组导致option元素在循环迭代时被逐个添加到DOM。敲除尝试通过检查它的值来保留选定的选项。在第一次迭代之后,所选的option具有值“Mr”。在第三次迭代之后,另一个option的值为“Mr”,所以Knockout认为它是之前选择的选项并将其选中。

这是一个link to a fiddle显示问题。应该选择“默认值”选项,但不是。如果单击该按钮再次添加具有相同值的另一个选项,该选项将变为选中状态,但根据文档,该选项不应该这样。

我的问题是,如何防止这种行为?

回答

3

为什么你要将物品逐一放入数组中?你可以只是做:的

view.titles(data); 

代替

for(var i = 0; i < data.length; i++) { 
    view.titles.push(data[i]); //Push titles into observable array 
} 

这也将解决您的问题 - 第一个项目将被默认选择。此外,如果您不打算向该阵列添加新项目,则可以使用ko.observable而不是ko.observableArray

更新: Knockoutjs似乎不喜欢具有相同值的多个选项。如果您将值绑定添加到选择标签(它将选择第三项,而不是第一项),我的代码将无法正常工作。但是,由于knockoutjs允许你通过值绑定来访问选中的对象,所以你可以通过值绑定去除optionsValue绑定和访问值:jsfiddle.net/ej9Ue/1

+0

啊,是的,它确实在最初修复它。但是当你添加新的选项时,它并没有帮助。看到这个更新的小提琴:http://jsfiddle.net/YuQsz/2/当点击“添加”时,“默认值”应该保持选择,但不是。 – 2012-02-06 16:24:45

+0

这肯定解决了初始数据的问题,但原始问题突出显示了Knockout.js选择先前选择的选项的方式中的怪癖/缺陷。它只检查元素的值,如果多个选项具有相同的值(这是一个有效的用例),它可以选择错误的值。一个可能的解决方案是在决定匹配之前检查价值并显示文本。这通过添加具有相同值的新选项而突出显示,但显示文本不同。 – adpd 2012-02-06 16:25:13

+0

你说得对,knockoutjs似乎并不喜欢具有相同价值的多个选项。如果您将值绑定添加到选择标签(它将选择第三项,而不是第一项),我的代码将无法正常工作。但是,由于knockoutjs允许你通过值绑定来访问选中的对象,你可以通过值绑定来移除optionsValue绑定和访问值:http://jsfiddle.net/ej9Ue/1/ – 2012-02-06 17:26:39