【问题标题】:Computed observable does not get notified of change计算的 observable 没有收到更改通知
【发布时间】:2014-02-05 11:29:48
【问题描述】:

可以在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 与 HistoryEntry 对象的可观察数组一起存储在父 ViewModel 上:

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 中尚不存在的 User(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);

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

同样,我希望当我添加 User(18) 时,HistoryEntry 与 User(18) 的计算 observable 将更新为 User(18) 的名称。

不幸的是,它没有。

问题

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

【问题讨论】:

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


    【解决方案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 跟踪计算中使用的所有可观察对象,因为您使用的是底层用户对象,它没有对用户的引用。因此,只有当它使用的 observable 之一发生更改时,才会更新计算值。

    【讨论】:

    • 在您的小提琴中,添加 User(18) 后,我没有看到历史表中出现 User(18) 的名称。历史表的最后一个条目应该是18 (18) Bill,但它是18 (18)
    • 是的,我已经编辑了答案。我把解包代码放错地方了。
    • 这很奇怪。当我单击“已进行编辑”时,它实际上并没有刷新您的答案!我看到它现在工作。如果你愿意,你能解释一下为什么我需要在计算的 observable 中使用unwrap 吗?谢谢!
    • 完美。这就说得通了。再次感谢!
    猜你喜欢
    • 2017-03-05
    • 1970-01-01
    • 2019-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-15
    • 2014-06-21
    相关资源
    最近更新 更多