3

我正在尝试实现一个HasOpenIssues计算的 observable,它绑定到一个 UI 元素,如果嵌套的 observableArray 的任何成员满足条件,该元素就会更新,并且无法使其工作。我正在使用 KO 2.2.0。

我的视图模型有一个 observableArray of Visits;每个访问都有一个 observableArray of Issues;每个Issues数组都可以包含Issue的实例,它有一个可观察的IsFixed属性。我还有一个计算出的 observable LatestVisit,它返回Visits数组中的最后一次访问:

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

所有这些都开始为空,在 I 之前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,因为Visits尚未填充数组,也无法观察到数组,因为尚未填充Issues其父级。Visit在我初始化之后,这些结构有数据,我需要更新HasOpenIssues以反映初始数据的状态。

然后,我允许用户向 中添加新IssuesLatestVisit,并将新的或现有的标记IssuesFixed。所以我也需要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后没有任何反应。

关于如何实现这一点的任何建议?

谢谢!

4

1 回答 1

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值中。

人为的演示 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);

人为的演示 2

于 2013-01-19T06:32:28.913 回答