2012-12-07 68 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 –