gpt4 book ai didi

knockout.js - 复杂对象 selectedObject 的选项绑定(bind)始终不在列表中

转载 作者:行者123 更新时间:2023-12-04 11:06:39 25 4
gpt4 key购买 nike

我经常有这样的对象:

var objectToMap = {
Id: 123,
UserType:{
Id: 456,
Name:"Some"
}
};

当我需要在用户界面中修改此对象时,我想从某个列表中进行选择。例如数组:
var list = [
{Id:456, Name: "Some"},
{Id:567, Name: "Some other name"}];

我使用选项绑定(bind),类似这样:
<select data-bind="options: list, optionsText: 'Name', value: UserType, optionsCaption: 'Select...'"></select>

问题是, knockout 认为 objectToMap {Id: 456, Name:"Some"} 中的 UserType 与列表 {Id:456, Name:"Some"} 中的对象不同。因此,UserType 会自动从列表中获取未定义但不需要的选项。

我以这种方式克服了问题:我使用 ko.utils.arrayFirst 在列表中找到项目并替换 objectToMap 中的 UserType。但这对我来说很难看,需要额外的编码。有更好的方法吗?

最佳答案

即使我认为 knockout 行为是正确的,正如我在评论中提到的,在这里您有几种方法可以解决您的问题(请注意,下面的所有代码都删除了错误检查;例如,您应该处理没有在列表中找到具有给定 id 的项目,下面的代码没有)。

您还可以创建一个自定义 bindingHandler,它确保属性值设置为列表属性中的项目,基于其他形式的相等性(例如它们的 JSON 表示相等)。但是,对我来说,感觉好像这种逻辑(将属性值与列表属性中的项目匹配)更适合 View 模型或潜在的扩展器,因为这些方法比涉及 bindingHandler 更容易创建单元测试对此的逻辑。

备选方案 1 - 使用 optionsValue
使用 optionsValue绑定(bind),您可以将选择列表设置为绑定(bind)到实际 ID。这在许多方面实际上是“正确”的方式,因为 objectToMap可能不应该包含整个 UserType而是只包含 id。您将添加一个 computed viewModel 上的属性得到正确的 UserType基于身份证。

self.myObject = {
id: 9348,
userTypeId: ko.observable(2)
};
//Add the userType computed property to the object
self.myObject.userType = ko.computed(function(){
var id = self.myObject.userTypeId();
return self.items.filter(function(item){
return item.id === id;
})[0];
});

然后,您将绑定(bind)到 userTypeId 属性,如下所示:
<select data-bind="options:items, value: myObject.userTypeId, optionsValue: 'id', optionsText: 'name'">
</select>

这段代码可以在 jsfiddle 中测试: http://jsfiddle.net/6Sg29/

备选方案 2 - 创建查找扩展器

如果您真的不想为您的对象添加另一个属性,您可以创建一个一次性查找扩展器,它会根据使用 id 查找正确项目的比较函数从列表中查找值。请注意,此解决方案将隐藏不匹配的数据,例如,如果对象上的项目与列表中的项目之间的名称属性不同。

这种扩展器的一个例子是:
ko.extenders.oneTimeLookup = function(target, options) {
var comparePropertyName = options.compare;
var item = target();
var foundItem = options.list.filter(function(listItem){
return item[comparePropertyName] === listItem[comparePropertyName];
})[0];
target(foundItem);
return target;
};

扩展器的使用如下:
self.myObject = {
id: 9348,
userType: ko.observable({
id: 2,
name: 'OriginalName'
}).extend({ oneTimeLookup: { list: self.items, compare: 'id' } })
};

在这种情况下,绑定(bind)可以只是一个普通的 optionsvalue 绑定(bind)指向 userType已扩展的 observable,因为我们已经执行了查找
<select data-bind="options:items, value: myObject.userType, optionsText: 'name'">
</select>

这段代码可以在 http://jsfiddle.net/qGFQ7/ 的 jsfiddle 中进行测试。

备选方案 3 - 在对象创建时进行手动查找。

这是您已经在使用的解决方案,在执行任何绑定(bind)之前,您需要手动查找并用列表中的项目替换对象。这类似于备选方案 2,但可重用性较低。哪一个更清楚地说明了您的意图,您必须自己决定。

概括

我建议使用第一种方法,因为原始对象可能不应该保留对完整项目的引用,因为您有一个要从中检索项目的查找列表。在第二种和第三种方法中,您只是丢弃了可能隐藏潜在错误的数据。但这只是我对这个问题的总体看法,当然在某些特定情况下我会考虑替代方案 2 或 3。

关于knockout.js - 复杂对象 selectedObject 的选项绑定(bind)始终不在列表中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22828533/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com