我有一个在数据库的表行上构造的对象。它具有在该条目中找到的所有属性以及几个ko.computed,它们是输入字段和显示内容之间的中间层。我需要它们才能为某些字段值翻译外键。
问题如下:其中一个属性是字符串的ID。我用计算机检索该ID。现在在计算中将有一个如下所示的值:'option1 | option2 | option3 | option4'
我希望用户能够更改选项,添加新选项或交换它们,但我还需要监视用户正在做什么(至少当他添加,删除或移动一个属性时)。因此,我创建了一个可观察的数组,我将以一种允许我监视用户操作的方式绑定它。然后数组将订阅计算所以它也会更新数据库中的值。
部分代码:
function Control(field) {
var self = this;
self.entry = field; // database entry
self.choices = ko.observableArray();
self.ctrlType = ko.computed({
read: function () {
...
},
write: function (value) {
if (value) {
...
}
},
owner: self
});
self.resolvedPropriety = ko.computed({
read: function () {
if (self.ctrlType()) {
var options = str.split('|');
self.choices(createObservablesFromArrayElements(options));
return str;
}
else {
return '';
}
},
write: function (value) {
if (value === '') {
//delete entry
}
else {
//modify entry
}
},
deferEvaluation: true,
owner: self
});
self.choices.subscribe(function (newValue) {
if (newValue.length !== 0) {
var newStr = '';
$.each(newValue, function (id, el) {
newStr += el.name() + '|';
});
newStr = newStr.substring(0, newStr.lastIndexOf("|"));
if (self.resolvedPropriety.peek() !== newStr) {
self.resolvedPropriety(newStr);
}
}
});
self.addChoice = function () {
//user added an option
self.choices.push({ name: ko.observable('new choice') });
};
self.removeChoice = function (data) {
//user removed an option
if (data) {
self.choices.remove(data);
}
};
...
}
这种组合有效,但不是我想要的。这是一种循环行为,它会触发太多次。这会给用户的操作带来一些重载,因为对数据库有很多请求。
我错过了什么?或者有更好的方法吗?
答案 0 :(得分:0)
来自knockout computed observable documentation
...在依赖链中包含循环是没有意义的。
我从帖子中解释的基本功能:
因此,我提供了一个功能的骨架示例,除了最后一个,您描述了@ JSfiddle将更改应用到数据库的能力可以通过多种方式解决;除非您愿意牺牲连接开销,否则所有这些都不应包括对任何更改数据的计算或订阅。通过将数据(我假设可以在一个服务调用中收集)格式化为一个漂亮的嵌套可观察视图模型并传递适当的可观察量,您可以排除对任何ko.computed
的需求。
<强> JS 强>:
var viewModel = {
availableFields : ko.observableArray([
ko.observable({fieldId: 'Field1',
properties: ko.observableArray([{propertyName: "Property 1.1"}])}),
ko.observable({fieldId: 'Field2',
properties: ko.observableArray([{propertyName:"Property 2.1"},
{propertyName:"Property 2.2"}])})]),
selectedField: ko.observable(),
addProperty: function() {
var propertyCount = this.selectedField().properties().length;
this.selectedField().properties.push({propertyName: "Property " + propertyCount})
},
};
ko.applyBindings(viewModel);
$("#field-properties-list").sortable({
update: function (event, ui) {
//jquery sort doesnt affect underlying array so we have to do it manually
var children = ui.item.parent().children();
var propertiesOrderChanges = [];
for (var i = 0; i < children.length; ++i) {
var child = children[i];
var item = ko.dataFor(child);
propertiesOrderChanges.push(item)
}
viewModel.selectedField().properties(propertiesOrderChanges);
}
});
<强> HTML 强>:
<span>Select a field</span>
<select data-bind='foreach: availableFields, value: selectedField'>
<option data-bind='text: $data.fieldId, value: $data'></option>
</select>
<div style="padding: 10px">
<label data-bind='text: "Properties for " + selectedField().fieldId'></label>
<button data-bind='click: $root.addProperty'>Add</button>
<ul id='field-properties-list' data-bind='foreach: selectedField().properties'>
<li style = "list-style: none;">
<button data-bind="click: function() { $root.selectedField().properties.remove($data) }">Delete</button>
<input data-bind="value: $data.propertyName"></input>
</li>
</ul>
</div>