2013-01-19 88 views
3

我試圖實現HasOpenIssues計算的observable綁定到UI元素,該元素更新如果嵌套的observableArray的任何成員滿足條件,並且無法獲取它工作。我正在使用KO 2.2.0。初始化嵌套數據後,Knockout computed observable不會更新

我的viewmodel有一個observableArray 訪問;每個訪問有一個可觀察數組問題;每個問題數組可以包含問題的實例,該實例具有可觀察的IsFixed屬性。我也有一個計算觀察到的LatestVisit,返回最後訪問訪問陣列:

function myVM(initialData) { 
    var self = this; 

    var Issue = function(id, isFixed, description) { 
     var self = this; 
     self.Id    = id; 
     self.IsFixed  = ko.observable(isFixed); 
     self.Description = ko.observable(description); 
    }; 
    var Visit = function(id, visitDate, issues) { 
     var self = this; 
     self.Id    = id; 
     self.VisitDate  = ko.observable(visitDate); 
     self.Issues   = ko.observableArray([]); 

     // init the array 
     issues && ko.utils.arrayForEach(issues, function(issue) { 
      self.addIssue(issue.Id, issue.Fixed, issue.Description); 
     }); 
    } 
    Visit.prototype.addIssue = function(id, isFixed, description) { 
     this.Issues.push(new Issue(id, isFixed, description)); 
    }; 

    self.LatestVisit    = ko.computed(function() { 
     var visits = self.Visits(); 
     return visits[ visits.length - 1 ]; 
    }); 
... vm continues 

所有這些開始是空的,在此之前我ko.applyBindings(),我從服務器獲取一些初始數據並把它作爲參數傳遞給我的視圖模型,它使用它來初始化各個觀測:

... continued from above... 
    self.init = function() { 
     // init the Visits observableArray 
     ko.utils.arrayForEach(initialData.Visits, function(visit) { 
      self.Visits.push(new Visit(visit.Id, visit.InspectionDateDisplay, visit.Issues)); 
     }); 
     ... more initialization... 
    }; 
    self.init(); 
} 

function registerVM() { 
    vm = new myVM(initialDataFromServer); 
    ko.applyBindings(vm); 
} 

因此,在過程中的一個點,我不能觀察LatestVisit,S因爲Visits數組尚未填充,因此數組尚未填充,因爲其父項Visit尚未填充。我初始化後,這些結構有數據,我需要更新HasOpenIssues以反映初始數據的狀態。

然後,我允許用戶將新的Issues添加到LatestVisit,並將新的或現有的Issues標記爲Fixed。所以我也需要HasOpenIssues來對這些變化做出反應。

我試圖添加計算爲在視圖模型的根的性質的HasOpenIssues,所述Visits陣列上,在Visit原型,並直接在LatestVisit計算,並沒有工作。它看起來是這樣的:

self.LatestVisit().HasOpenIssues = ko.computed(function() { 
     var unfixed = ko.utils.arrayFirst(this.Issues(), function(issue) { 
      return issue.IsFixed == false; 
     }); 
     console.log('HasUnfixedIssues:', unfixed); 
     if (unfixed) { return true; } 
    }); 

如果我讓它初始化之前運行,我得到的

Uncaught TypeError: Object [object Window] has no method 'Issues' 

一些變化,或者如果我添加, root, { deferEvaluation: true }參數計算的函數調用,我得到

Uncaught TypeError: Cannot set property 'HasUnfixedIssues' of undefined 

如果我離開關(),如self.LatestVisit.HasOpenIssues,然後我得到

Uncaught TypeError: Object [object Window] has no method 'Issues' 

如果我不使用延期選項。如果我添加它,初始化時不會出現錯誤,但稍後更新Issues時不會發生任何錯誤。

有關如何實現此目的的任何建議?

謝謝!

回答

1

我會讓HasOpenIssues屬於所有訪問。這樣,您可以檢查是否有任何訪問存在公開問題,而不僅僅是最新問題。

function Visit(id, visitDate, issues) { 
    this.Id    = id; 
    this.VisitDate  = ko.observable(visitDate); 
    this.Issues   = ko.observableArray(); 

    this.HasOpenIssues = ko.computed(function() { 
     var unfixed = ko.utils.arrayFirst(this.Issues(), function (issue) { 
      return !issue.IsFixed(); 
     }); 
     return unfixed !== null; 
    }, this); 

    // init the array 
    this.Issues(ko.utils.arrayMap(issues, function (issue) { 
     return new Issue(issue.Id, issue.Fixed, issue.Description); 
    })); 
} 

這樣一來,即使有任何問題,你沒有嘗試將屬性添加到undefined值。

contrived demo 1


如果你只關心最新的訪問,然後安裝在HasOpenIssues屬性的LatestVisit是把它的好地方。你只需要做對。檢查您是否有LatestVisit,然後返回適當的值,否則返回一些默認值(在這種情況下爲false)。

this.LatestVisit.HasOpenIssues = ko.computed(function() { 
    var visit = this.LatestVisit(); 
    if (!visit) { 
     return false; 
    } 
    var unfixed = ko.utils.arrayFirst(visit.Issues(), function (issue) { 
     return !issue.IsFixed(); 
    }); 
    return unfixed !== null; 
}, this); 

contrived demo 2

+0

該死,我想首先檢查對象存在 - 得更加小心的!謝謝,這現在工作正常! – Val