计算的observable不会收到有关更改的通知

时间:2014-01-16 13:58:05

标签: javascript knockout.js ko.observablearray computed-observable

可以在此JSFiddle查看所有即将关注的代码。我已经从这个问题中省略了HTML数据绑定和模板,但它们可以在小提琴中看到。我不认为它们与说明问题有关。


简介

我正在尝试将计算的observable链接到我用作HashMap的另一个对象。

具有计算的observable的对象是HistoryEntry

function HistoryEntry(userId, users) {
    this.UserId = ko.observable(userId);

    this.User = ko.computed(function () {
        if (!users[this.UserId()]) return '(' + this.UserId() + ')';
        return '(' + this.UserId() + ') ' + users[this.UserId()].Name();
    }, this);
}

HistoryEntry包含UserId,它在我的JavaScript对象中充当HashMap的查找值。 users是对ViewModel中包含的此HashMap的引用。

HashMap包含由User键入的UserId个对象。 User对象如下:

function User(id, name) {
    this.Id = ko.observable(id);
    this.Name = ko.observable(name);
}

这个想法是计算的observable HistoryEntry.User()将从这个HashMap中相应的User对象中查找名称。

HashMap存储在父ViewModel上,以及HistoryEntry对象的可观察数组:

function ViewModel() {
    this.users = ko.observable({
        '16': new User(16, 'Jack'),
        '17': new User(17, 'Jill')
    });

    this.history = ko.observableArray([
        new HistoryEntry(16, this.users()),
        new HistoryEntry(17, this.users()),
        new HistoryEntry(18, this.users())
    ]);
}

var view = new ViewModel();
ko.applyBindings(view);

问题

正如您在上面所看到的,我只创建了两个用户,但我有三个历史记录条目,每个条目都指向不同的用户。其中一个条目引用了HashMap中尚不存在的用户(18)。

在我的示例中,我将User(16)的名称从“Jack”更改为“John”并添加User(18):

setTimeout(function () {
    view.users()[16].Name('John');
    view.users()[18] = new User(18, 'Bill');
    view.users.valueHasMutated();
    view.history.valueHasMutated();
}, 1000);

这会正确更新具有指向User(16)的计算observable的HistoryEntry

同样,我预计当我添加User(18)时,带有计算的observable到User(18)的HistoryEntry将更新为User(18)的名称。

不幸的是,它没有。

问题

  1. 我想更深入地了解为什么指向用户(18)的HistoryEntry没有收到有关更改的通知,因为用户(18)确实存在。
  2. 此外,我需要找到一个解决方案,当用户(18)添加到用户HashMap时,它将更新指向User(18)的HistoryEntry

1 个答案:

答案 0 :(得分:1)

HistoryEntry不会更新,因为你没有在计算中展开users

尝试更改

new HistoryEntry(18, this.users())

new HistoryEntry(16, this.users)

然后将HistoryEntry更改为:

function HistoryEntry(userId, users) {
    this.UserId = ko.observable(userId);

    this.User = ko.computed(function () {
        var usersArr = ko.unwrap(users);
        if (!usersArr[this.UserId()]) return '(' + this.UserId() + ')';
        return '(' + this.UserId() + ') ' + usersArr[this.UserId()].Name();
    }, this);
}

请参阅http://jsfiddle.net/W6nRe/

Computeds跟踪计算中使用的所有可观察对象,因为您使用的是基础用户对象,它没有对用户的引用。因此,只有当它使用的一个可观察量发生变化时,计算才会更新。