【问题标题】:KnockoutJS selectedOptions not showing upKnockoutJS selectedOptions 未显示
【发布时间】:2015-01-13 04:48:52
【问题描述】:

我正在使用 KnockoutJS 来管理我的 Web 前端。我正在编写一个 CRUD/Admin 站点,但我遇到了 selectedOptions 绑定问题。

案例:

  • 视图模型具有form.products.allform.products.selected 可观察对象。这两个都是ko.mapping生成的。

  • HTML 表单具有表单的多选:

    <select required="" multiple="" data-bind="options: products.all, optionsText: function (item) { return item.value.name.unName(); }, selectedOptions: products.selected" class="form-control">
    
  • HTML 表单正确显示所有选项。

  • HTML 表单在加载时显示选定的选项。特别是,如果我检查 viewModel 对象,我可以看到正确的对象在加载时被加载到 products.selected 数组中。但是多选不会自动选择它们。

  • 如果我选择表单中的对象,然后检查 products.selected 可观察对象,我确实会看到数组中的对象。

  • 如果我发布表单,正确的对象最终会出现在数据库中,然后在下一页加载时出现在 viewModel 对象中(因此循环中唯一缺少的部分实际上是基于products.selected 中的内容。

我做错了什么?我看到了相互矛盾的建议,其中一些已经过时,所以我不确定如何继续。

【问题讨论】:

  • 文档说“同样,假设它是您的视图模型上的一个可观察数组,那么每当您向该数组添加或删除(例如,通过推送或拼接)项目时,UI 中的相应项目将变为选择或取消选择。这是一种 2 向绑定。"
  • 你能提供一个小提琴之类的吗?
  • @nomen 你没理我的评论。

标签: javascript html knockout.js


【解决方案1】:

selectedOptions 绑定按设计工作。

您的错误很可能是您的 selected observable 不包含 相同 对象(即,all 中对象的引用),而只是对象具有相同的属性值。

Knockout 通过对象标识维护绑定,不做任何其他比较。

考虑这个简单的例子:

var vm = {
    products: {
        selected: ko.observableArray(),
        all: ko.observableArray([
            {
                value: {
                    name: {
                        unName: ko.observable("Foo")
                    }
                }
            }, {
                value: {
                    name: {
                        unName: ko.observable("Bar")
                    }
                }
            }
        ])
    }
};
vm.products.selected.push(vm.products.all()[1]);
ko.applyBindings(vm);
pre {
  font-size: small;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>

<select required="" multiple="" class="form-control" data-bind="
    options: products.all, 
    optionsText: function (item) { 
        return item.value.name.unName(); 
    }, 
    selectedOptions: products.selected
"></select>

<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

不相关的旁注:尽量避免在绑定属性中定义函数。它丑陋,效率低下,可能重复并且不是很惯用。在视图模型上做一个对应的属性,比如这样:

function Product(data) {
    ko.utils.extend(this, data);
    this.displayName = this.value.name.unName;
}

<div data-bind="with: products">
    <select required="" multiple="" class="form-control" data-bind="
        options: all, 
        optionsText: 'displayName', 
        selectedOptions: selected
    "></select>
</div>

【讨论】:

  • 是的,这确实有道理。据推测,解决方案是为 products.allproducts.selected 自定义 ko.mapping 对象创建(即将它们编组为特定于 viewModel 的表示)
  • 是的,例如。假设您从服务器收到两个列表,我首先将所有产品映射到products.all,并在此过程中建立一个索引。接下来我将迭代selected 产品,从索引中选择相应的实例并将它们推送到products.selected
  • 终于……这太令人沮丧了。很好的答案,特别是因为您解释了相同对象和仅具有相同属性值的对象之间的区别。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-11
  • 2011-05-12
  • 1970-01-01
  • 2020-11-16
  • 2012-10-12
  • 2019-02-20
  • 1970-01-01
相关资源
最近更新 更多