为什么分配相同的值会触发订阅处理程序?

时间:2014-04-16 08:11:48

标签: javascript knockout.js

我有一个带有observalbe项目数组的简单viewmodel,以及一个包含所选项目的observable。我订阅了所选项目的更改,我可以在我的测试中看到,即使我一次又一次地分配相同的值,处理程序也会被触发,所以不应该有任何改变。以下代码显示了3个相同的警报"更改为..."文本。

view.SelectedItem(view.Items()[0]);
view.SelectedItem.subscribe(function(newValue) {
   alert("changed to " + ko.toJSON(newValue));
});
view.SelectedItem(view.Items()[0]);
view.SelectedItem(view.Items()[0]);
view.SelectedItem(view.Items()[0]);

这是demo fiddle

3 个答案:

答案 0 :(得分:1)

显然,选择一个项目,即使它与已经选择的项目相同,也会触发更改事件,调用订阅时指定的功能。

如果您希望在即将更改之前收到可观察值的通知,您可以订阅beforeChange事件。例如:

view.SelectedItem.subscribe(function(oldValue) {
    alert("The previous value is " + oldValue);
}, null, "beforeChange");

<强> Source

这可以帮助您确定值是否已更改。

答案 1 :(得分:1)

您可以创建函数来访问旧值和新值以进行比较:

ko.subscribable.fn.subscribeChanged = function(callback) {
    var previousValue;
    this.subscribe(function(oldValue) {
        previousValue = oldValue;
    }, undefined, 'beforeChange');
    this.subscribe(function(latestValue) {
        callback(latestValue, previousValue);
    });
};

您可以使用ko扩展名将此功能添加到某个文件中。我曾经在stackoverflow上找到它,但现在无法记住链接。然后你可以像这样使用它:

view.SelectedItem.subscribeChanged(function(newValue, oldValue) {
    if (newValue.Name != oldValue.Name || newValue.Quantity != oldValue.Quantity) {
        alert("changed to " + ko.toJSON(newValue));
    }   
});

Fiddle

答案 2 :(得分:0)

我最终根据论坛上的帖子创建了自己的方法:

// Accepts a function(oldValue, newValue) callback, and triggers it only when a real change happend
ko.subscribable.fn.onChanged = function (callback) {
  if (!this.previousValueSubscription) {
    this.previousValueSubscription = this.subscribe(function (_previousValue) {
      this.previousValue = _previousValue;
    }, this, 'beforeChange');
  }
  return this.subscribe(function (latestValue) {
    if (this.previousValue === latestValue) return;
    callback(this.previousValue, latestValue);
  }, this);
};