我正在尝试实现一个HasOpenIssues
计算的observable,它绑定到一个UI元素,如果嵌套的observableArray的任何成员满足条件,则该元素会更新,并且无法使其工作。我正在使用KO 2.2.0。
我的viewmodel有一个observableArray 访问次数;每个访问都有一个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()
之前,我从服务器获取一些初始数据并将其作为参数传递给我的viewmodel,它使用它来初始化各种observable:
... 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
,因为Visits
数组尚未填充,而Issues
数组也没有,因为它尚未填充父Visit
。初始化后,这些结构有数据,我需要更新HasOpenIssues
以反映初始数据的状态。
然后,我允许用户向Issues
添加新的LatestVisit
,并将新的Issues
标记为Fixed
。所以我也需要HasOpenIssues
来对这些变化做出反应。
我尝试在HasOpenIssues
数组的Visits
数组上,直接在{{Visit
数组上添加LatestVisit
计算为视图模型根的属性1}}计算,没有工作。它看起来像这样:
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
时没有任何反应。
有关如何实施此建议的任何建议吗?
谢谢!
答案 0 :(得分: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
值。
如果您只关心最近的访问,那么将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);