【问题标题】:knockoutjs: order matters in computed observable?knockoutjs:计算 observable 中的顺序很重要?
【发布时间】:2016-11-03 03:09:51
【问题描述】:

我有一个计算的 observable,由于计算 observable 函数中 observable 的顺序,它不会更新。单击分支不会更新叶子上的计算 observable。这是故意的吗?

https://jsfiddle.net/acL3f1qp/9/

javascript:

(function() {

  function Branch(viewModel) {
    var self = this;
    self.isAllowed;
    self.isChecked = ko.observable();
    self.isChecked.subscribe(function(newValue){
        //is updating?
      null;
    });
    self.leaves = [];
    self.allowLeaves = ko.computed(function() {
      return viewModel.allowLeaves() && (!self.isAllowed || self.isChecked());
    });
  }

  function Leaf(branch) {
    var self = this;
    var isCheckedInternal = ko.observable();
    self.isAllowed;
    self.isChecked = ko.computed({
            read: function() {
            return branch.allowLeaves() && isCheckedInternal();
            },
        write: function(value) {
            isCheckedInternal(value);
        }
    });
  }

  function ViewModel() {
    var self = this;
    var branch;
    var leaf;
    self.allowLeaves = ko.observable(true);
    self.branches = [];
    branch = new Branch(self);
    branch.isAllowed = true;
    branch.isChecked(true);
    leaf = new Leaf(branch);
    leaf.isAllowed = true;
    leaf.isChecked(true);
    branch.leaves.push(leaf);
    self.branches.push(branch);
  }

  ko.applyBindings(new ViewModel());

})();

html:

<div>
  <label>
    <input type="checkbox" data-bind="checked: allowLeaves" />
    <span>allow leaves</span>
  </label>
</div>
<div class="indent" data-bind="foreach: branches">
  <div>
    <label>
      <input type="checkbox" data-bind="checked: isChecked, visible: isAllowed" />
      <span>branch</span>
    </label>
  </div>
  <div class="indent" data-bind="foreach: leaves">
    <div>
      <label>
        <input type="checkbox" data-bind="checked: isChecked, visible: isAllowed" />
        <span>leaf</span>
      </label>
    </div>
  </div>
</div>
<br />
clicking on "branch" does 

不在叶子上计算更新!

【问题讨论】:

  • 您的 self 与 viewModel 的不同部分有关,因此 self.allowBranch 在您进行测试的位置未定义。
  • 一些补充说明。 - 你确定其中一些数组(branchesleaves)不应该是observable数组吗? - isCheckedInternal var 是不可观察的,因此更改它永远不会触发计算更新,那么它的意义何在(至少在这个重现中?)。 - Leaf isChecked 是一个readonly计算出来的,但是你在视图中有一个双向绑定?
  • 无论如何,在构建视图模型时,计算函数将运行一次,设置所有依赖项,因为其他可观察对象被调用以获取它们的值。由于短路逻辑运算符以及早期返回语句,初始运行可能无法正确设置依赖关系。尝试重新排序您的 observable getter(例如,从简单地调用它们并在计算函数开始时将它们的值保存在局部变量中)看看这是否是您的问题。
  • @brianlmerrit 你是对的,我的例子中有一个错误。我已经更新了这个例子来展示我的问题。这似乎是由于在实例化后设置了分支的属性。
  • @Jeroen 我认为逻辑操作的短路是问题的原因。谢谢!

标签: knockout.js


【解决方案1】:

计算中的可观察对象的顺序仅对构建 dependencies 很重要;

在这个计算中:

ko.pureComputed(function(){
  return a() && b(); 
}

(假设 ab 是可观察的并返回 truefalse

如果 a 返回 false,则不会评估 b(因为 && 运算符是惰性的)并且 KO 不会创建对 b 的依赖,只会创建对 a 的依赖。

这很好 - 对 b 的任何更改都不会影响此计算的值,因此重新评估将浪费资源。

如果 a 更新为返回 true,KO 将重新评估计算(因为它确实依赖于 a)并且在这样做时需要找出 b 具有什么值,然后创建一个依赖。


至于您的小提琴-据我所知,您的问题是分支上的isChecked observable 没有以任何方式链接到计算的allowLeaves。所以它不会得到更新。

如果您将Branch 的实现更改为看起来更像LeafisCheckedInternal,如下所示:

function Branch(viewModel) {
  var self = this;
  self.isAllowed = ko.observable();
  var isCheckedInternal = ko.observable();

  self.leaves = [];
  self.allowLeaves = ko.pureComputed({
    read: function() {
      return viewModel.allowLeaves() && isCheckedInternal();
    },
    write: function(val){
      isCheckedInternal(val);
  }});
}

然后将选中的绑定到allowLeaves 然后它似乎按预期工作。

我有一个 fiddle 正在工作...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-17
    • 1970-01-01
    • 1970-01-01
    • 2014-07-03
    • 2014-02-27
    • 2014-10-23
    • 2017-05-27
    • 1970-01-01
    相关资源
    最近更新 更多