2014-10-07 42 views
0

考慮下面的淘汰賽代碼:訪問其依賴的訂閱的一個計算

function ViewModel() { 
    this.firstName = ko.observable(""); 
    this.lastName = ko.observable(""); 
    this.dummyDependency = ko.observable(false); 
    this.fullName = ko.computed(function() { return this.dummyDependency() ? this.firstName() + " " + this.lastName() : ""; }, this); 

    var self = this; 
    this.lastName.subscribe(function(newValue) { 
    alert(self.fullName()); 
    }); 
}; 

var myModel = new ViewModel(); 
myModel.dummyDependency(true); 
myModel.firstName("Joe"); 
myModel.lastName("Smith"); 
// ---> alerts "Joe " 
alert(myModel.fullName()); 
// ---> alerts "Joe Smith" correctly 

下面是該代碼來測試一個fiddle

我明白這種行爲背後的原因,但我不知道如何克服這一點。其原因是,最初當計算運行,它沒有找到firstNamelastName爲依賴(因爲錯誤的標誌),所以它不會訂閱。

因此,當我訂閱lastName,我的訂閱將是訂閱列表中的第一個lastName。然後,當我改變標誌true,這將迫使計算的重新評估,並現在預訂這兩個firstNamelastName其訂閱會後我的列表。因此,當我更改姓氏時,我的訂閱在計算之前觸發,因此我無法獲取最新值。

這個例子非常簡單,我的真實情況要複雜得多,不能重構或重新設計太簡單。有沒有人有任何想法或竅門如何解決這種行爲?

+0

究竟是你想實現什麼目標?您正在訂閱'lastName',但您正在進行影響並警告'fullName'的更改。如果你想跟蹤它的變化,你應該訂閱'fullName'。 – 2014-10-07 15:45:36

+0

@JeffMercado是的,這就是爲什麼我指出這只是一個愚蠢的示例代碼。在我的真實場景中,我無法訂閱計算,因爲它也可能因其他依賴關係而發生更改。 – 2014-10-07 15:47:30

+0

這就是關鍵,它的依賴關係可能會改變,但你的依賴關係不會改變。你依賴計算的可觀測值,你不應該關心它依賴於什麼。如果你有一個更具體的例子說明你想在這裏完成什麼,我們可能會引導你朝正確的方向發展。 – 2014-10-07 15:52:05

回答

0

最後我發現我在一個更深的地方做了一個糟糕的設計決定。我在@JeffMercado的評論中得到的指導指出了我如何處理複雜的依賴關係鏈的正確方向。關鍵是要確保我總是訂閱我直接使用的可觀察值(或計算可觀察值)。如果一個scneario不適合這個範例,那麼這個設計是不好的,必須重構。

在我的例子(這是真的只是demonstational提出)的重構是因爲訂閱了fullName計算,而不是作爲lastName簡單,因爲在訂閱的動作直接需要fullName

這裏是正確的版本:

function ViewModel() { 
    this.firstName = ko.observable(""); 
    this.lastName = ko.observable(""); 
    this.dummyDependency = ko.observable(false); 
    this.fullName = ko.computed(function() { return this.dummyDependency() ? this.firstName() + " " + this.lastName() : ""; }, this); 

    var self = this; 
    this.fullName.subscribe(function(newValue) { 
    alert(self.fullName()); 
    }); 
}; 

var myModel = new ViewModel(); 
myModel.dummyDependency(true); 
myModel.firstName("Joe"); 
myModel.lastName("Smith"); 
// ---> alerts "Joe Smith" as expected