如何在knockoutjs中实现复选框依赖

发布于 2025-01-04 17:06:25 字数 2163 浏览 0 评论 0原文

我有一组复选框

  • 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

终难愈 2025-01-11 17:06:25

checked 绑定绑定到数组时,它需要能够对其执行数组操作。因此,在这种情况下使用可写的计算可观察量会导致问题。

但是,您可以选择使用手动订阅来保持项目同步。

这是一个示例视图模型:

var ViewModel = function() {
    var self = this;
    this.items = ko.observableArray([
        { id: "A" },
        { id: "B" },
        { id: "C" },
        { id: "D" }
        ]);
    this.checked = ko.observableArray();
    this.checked.subscribe(function(newValue) {
        if (self.checked.indexOf("C") > -1) {
            if (self.checked.indexOf("A") < 0) {
               self.checked.push("A");
            }  
            if (self.checked.indexOf("B") < 0) {
               self.checked.push("B");
            }  
        }
    });

    this.shouldBeDisabled = function(item) {
         return (item.id === "B" || item.id ==="A") && self.checked.indexOf("C") > -1;     
    };
};

这是视图:

<ul data-bind="foreach: items">
    <li>
        <span data-bind="text: id"></span>
        <input type="checkbox" data-bind="attr: { value: id }, checked: $root.checked, disable: $root.shouldBeDisabled($data)" />
    </li>
</ul>

我使用 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:

var ViewModel = function() {
    var self = this;
    this.items = ko.observableArray([
        { id: "A" },
        { id: "B" },
        { id: "C" },
        { id: "D" }
        ]);
    this.checked = ko.observableArray();
    this.checked.subscribe(function(newValue) {
        if (self.checked.indexOf("C") > -1) {
            if (self.checked.indexOf("A") < 0) {
               self.checked.push("A");
            }  
            if (self.checked.indexOf("B") < 0) {
               self.checked.push("B");
            }  
        }
    });

    this.shouldBeDisabled = function(item) {
         return (item.id === "B" || item.id ==="A") && self.checked.indexOf("C") > -1;     
    };
};

Here is the view:

<ul data-bind="foreach: items">
    <li>
        <span data-bind="text: id"></span>
        <input type="checkbox" data-bind="attr: { value: id }, checked: $root.checked, disable: $root.shouldBeDisabled($data)" />
    </li>
</ul>

I used attr: { value: id } instead of value 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/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文