2012-12-07 69 views
1

假设你有以下JS:knockout.js - 何时计算项目重新计算依赖关系?

var vm = { 
    objects: ko.observable([]), 
    objectCount: ko.computed(function(){ 
     return vm && vm.objects().length; 
    }), 

    add: function() { 
     var current = vm.objects(); 
     current.push({});  
     console.log('current is', current); 
     vm.objects(current); 
     console.log("should recalculate here", vm.objectCount()); 
    } 
    }; 

而且下面的HTML:

<ul data-bind="foreach: objects"> 
    <li> 
     Object: <span data-bind="text: $index"></span> 
    </li> 
    </ul> 
    <button data-bind="click: add">Add Object</button> 
    <p> 
    Total number of objects: 
    <span data-bind="text: objectCount"></span> 
    </p> 

这是我的理解from reading the documentation因为之后我添加对象我叫objectCount(),它应该重新计算它的依赖关系。相反,它似乎从来没有执行该功能,只运行一次!

JSBin demonstrating a simplified version of my issue.

回答

2

这只是一个范围的问题。如果你重构你的脚本代码如下所示:

$(function(){ 
    var vm = function(){ 
    var self = this; 

    self.objects = ko.observable([]); 
    self.objectCount = ko.computed(function(){ 
     return self.objects().length; 
    }); 

    self.add = function() { 
     var current = self.objects(); 
     current.push({});  
     console.log('current is', current); 
     self.objects(current); 
     console.log("should recalculate here", self.objectCount()); 
    }; 
    }; 

    ko.applyBindings(new vm()); 
}); 

那么正确的变量的作用域和淘汰赛正确计算的依赖关系。如guigouz所述,当最初调用ko.computed时,vm未定义,因此它不能设置任何更改处理程序。

这里是the updated JSBin

4

定义你定义你的视图模型的工作原理后计算 - http://jsbin.com/welcome/58760/ - 这是因为该方法计算的观测工作(从KO文档)的。

  1. 每当你声明一个计算的可观察值时,KO立即调用 它的求值函数来获得它的初始值。
  2. 虽然您的评估函数正在运行,但KO会保留任意 可观测值(或可计算的可观察值)的日志,评估者读取其值 的值。
  3. 当您的评估者完成后,KO会为您所触及的观测值(或计算的观测值)设置订阅。
    订阅回调设置为使您的评估程序再次运行,
    将整个过程循环回到步骤1(处置不再适用的任何旧的
    订阅)。
  4. KO通知任何订户有关您计算的 可观察值的新值。

当实例化vm对象内部的observable时,其他属性还不存在。

+0

没错,但是第3点意味着它会重新计算,不是吗?尽管在更仔细的阅读中,它意味着价值被记录下来,并且只有在用户更新时才会更新(解释我的问题)。我想指出的是,虽然在你的例子中删除复选标记不起作用 - 因为这些也是可观察的,我不确定为什么是这种情况。 –

+1

但是当评估者完成时,你的vm对象上没有可观察的事物(他们还没有存在,因为var语句没有完成)。 checked()不起作用,因为您使用的是value:binding,而不是checked:在复选框上,这里是更新的小提琴 - http://jsbin.com/welcome/58799/ - 我还将对象更改为observableArray,这样ko只会在你推动它们时渲染新的元素,而不是重新渲染整个数组。 我还建议将你的viewmodels定义为函数,并将它们实例化为Josh提出的,但这并不能解释为什么它不起作用。 – guigouz

2

另一种方法是对ko.computed使用deferEvaluation选项。这将告诉Knockout等待计算出的可观察值,直到第一次使用。届时,vm将被定义。

objectCount: ko.computed(function(){ 
    return vm && vm.objects().length; 
}, null, { deferEvaluation: true }), 
+0

哦,好的提示,不知道那个。尽管我喜欢这个教程式,但我真的很希望他们也有一些API文档。 –

+0

'ko.computed'有一个简短的参考部分:http://knockoutjs.com/documentation/computedObservables.html#computed_observable_reference –