如何在knockoutjs中实现复选框依赖
我有一组复选框
- checkbox A
- checkbox B
- checkbox C
使用 foreach 数据绑定生成:
<input type="checkbox" data-bind="value: id, checked: $root.chkboxSelected" />
它们从 observableArray 获取其选中状态。因此,选中一个框会将相应的值添加到数组中,标准的knockoutjs可以正常工作。然后我想添加一个简单的规则:
如果检查了 C,则也必须检查 A 和 B。
在knockoutjs中添加这种逻辑的最干净的方法是什么?我尝试使用可写的可计算的可观察对象:
var viewModel = {
foo: observableArray(),
..
};
viewModel.chkboxSelected = ko.computed({
read: function() {
return this.foo();
},
write: function(value){
//add it if not added already
if($.inArray(value, this.foo()) < 0) {
this.foo.push(value);
}
// if C is present then A,B must be as well
if($.inArray("C", this.foo()) >= 0) {
if($.inArray("B", this.foo()) < 0) {
this.foo().push("B");
}
if($.inArray("A", this.foo()) < 0) {
this.foo().push("A");
}
}
},
owner: viewModel
});
在读取和写入函数上放置断点:读取被调用并且页面加载正常。但是,当我单击任何复选框时,我会收到以下错误(写入断点永远不会被命中):
knockout-2.0.0.debug.js:2297
Uncaught TypeError: Object function dependentObservable() {
if (arguments.length > 0) {
if (typeof options["write"] === "function") {
// Writing a value
var valueForThis = options["owner"] || evaluatorFunctionTarget; // If undefined, it will default to "window" by convention. This might change in the future.
options["write"].apply(valueForThis, arguments);
} else {
throw "Cannot write a value to a dependentObservable unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.";
}
} else {
// Reading the value
if (!_hasBeenEvaluated)
evaluateImmediate();
ko.dependencyDetection.registerDependency(dependentObservable);
return _latestValue;
}
} has no method 'push'
I have a group of checkboxes
- checkbox A
- checkbox B
- checkbox C
Generated with the foreach data binding:
<input type="checkbox" data-bind="value: id, checked: $root.chkboxSelected" />
Which take their checked state from an observableArray. So checking a box will add the corresponding value to the array, standard knockoutjs that works fine. I then wanted to add a simple rule:
if C is checked, then A and B must be checked as well.
What is the cleanest way to add this kind of logic in knockoutjs? I tried with a writable computable observable:
var viewModel = {
foo: observableArray(),
..
};
viewModel.chkboxSelected = ko.computed({
read: function() {
return this.foo();
},
write: function(value){
//add it if not added already
if($.inArray(value, this.foo()) < 0) {
this.foo.push(value);
}
// if C is present then A,B must be as well
if($.inArray("C", this.foo()) >= 0) {
if($.inArray("B", this.foo()) < 0) {
this.foo().push("B");
}
if($.inArray("A", this.foo()) < 0) {
this.foo().push("A");
}
}
},
owner: viewModel
});
Putting a breakpoint on the read and write functions: read gets called and the page loads fine. However, when I then click any checkbox I get the following error (the write breakpoint never gets hit):
knockout-2.0.0.debug.js:2297
Uncaught TypeError: Object function dependentObservable() {
if (arguments.length > 0) {
if (typeof options["write"] === "function") {
// Writing a value
var valueForThis = options["owner"] || evaluatorFunctionTarget; // If undefined, it will default to "window" by convention. This might change in the future.
options["write"].apply(valueForThis, arguments);
} else {
throw "Cannot write a value to a dependentObservable unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.";
}
} else {
// Reading the value
if (!_hasBeenEvaluated)
evaluateImmediate();
ko.dependencyDetection.registerDependency(dependentObservable);
return _latestValue;
}
} has no method 'push'
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当
checked
绑定绑定到数组时,它需要能够对其执行数组操作。因此,在这种情况下使用可写的计算可观察量会导致问题。但是,您可以选择使用手动订阅来保持项目同步。
这是一个示例视图模型:
这是视图:
我使用
attr: { value: id }
而不是value
来避免由值附加的事件处理程序绑定,因为值绑定旨在处理字段的更改。在本例中,我们只想设置 value 属性。示例如下:http://jsfiddle.net/rniemeyer/tQJMg/
When the
checked
binding is bound against an array, then it needs to be able to perform array operations against it. So, using a writeable computed observable in that case will cause an issue.However, you can opt to use a manual subscription to keep your items in sync.
Here is a sample view model:
Here is the view:
I used
attr: { value: id }
instead ofvalue
to avoid the event handler that would be attached by the value binding, as the value binding is designed to handle changes to a field. In this case, we only want to set the value attribute.Sample here: http://jsfiddle.net/rniemeyer/tQJMg/