在同一个可观察对象的订阅中获取先前的值

87

在Knockout中,是否可以在观察者的订阅(subscription)接收新值之前获取该可观察对象的当前值?

示例:

this.myObservable = ko.observable();
this.myObservable.subscribe(function(newValue){
    //I'd like to get the previous value of 'myObservable' here before it's set to newValue
});
5个回答

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

    this.subscribe(function (newValue) {
        callback(newValue, oldValue);
    });
};

使用如下方式:

MyViewModel.MyObservableProperty.subscribeChanged(function (newValue, oldValue) {

});

2
我对knockout还比较新,但我希望默认的订阅方式是这样设置的。或者说,当我第一次使用“subscribe”时,这个函数至少可以解决我的第一个问题。 - bkwdesign
1
这个问题在 https://github.com/knockout/knockout/issues/914 上有一些进展。看起来它将在3.4版本中发布。 - AlignedDev
2
如果被订阅的可观察值类型是数组,则必须对其进行切片,否则 oldValue 将始终与 newValue 相同。在此处检查一个工作示例:https://jsfiddle.net/david_freire/xmk6u9yn/4/ - David Freire
1
很棒。添加了一个返回值,它是一个带有dispose()函数的订阅对象。https://gist.github.com/30ff1f5c1adf215179b0046515f86e45 - Michael
哦,刚看到了关于 Git 的对话。 - Michael
@DavidFreire 如果数组包含对象,它仍然存在问题。我试图绕过它,但是很混乱。最后,我添加了一个额外的订阅来完全处理该值的JSON。 - br4nnigan

92

有一种方法可以像这样订阅先前的值:

this.myObservable = ko.observable();
this.myObservable.subscribe(function(previousValue){
    //I'd like to get the previous value of 'myObservable' here before it's set to newValue
}, this, "beforeChange");

这里的 this 代表什么? - Thanasis Ioannidis
@ThanasisIoannidis 它确保您可以在回调函数内访问相同的“this”值。否则,您需要事先将其保存到另一个名称中,例如 var self = this;(这也是一种完全有效的策略)。 - marcus

23

对Beagle90的回答进行小修改。始终返回订阅本身,以便能够访问dispose()方法。

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

    var subscription = this.subscribe(function (newValue) {
        callback(newValue, oldValue);
    });

    // always return subscription
    return subscription;
};

2
这是一个真正的进步,但是在返回值上调用.dispose只会处理第二个订阅,而不是 'beforeChange' 订阅。 - TRManderson

18

拉取请求 添加这个功能的代码比依赖于使用beforeChange事件更好。

感谢Michael Best提供了解决方案。

ko.subscribable.fn.subscribeChanged = function (callback) {
    var savedValue = this.peek();
    return this.subscribe(function (latestValue) {
        var oldValue = savedValue;
        savedValue = latestValue;
        callback(latestValue, oldValue);
    });
};

引用 Michael 的话:

我最初建议使用 beforeChange 来解决这个问题,但后来意识到它并不总是可靠的(例如,如果你在 observable 上调用了 valueHasMutated())。


4
我发现在可写的计算属性中,可以调用peek()方法获取之前的值。
类似这样(参见 http://jsfiddle.net/4MUWp):
var enclosedObservable = ko.observable();
this.myObservable = ko.computed({
    read: enclosedObservable,
    write: function (newValue) {
        var oldValue = enclosedObservable.peek();
        alert(oldValue);
        enclosedObservable(newValue);
    }
});

1
很遗憾,那样做行不通,因为当订阅回调被调用时,值已经改变,所以 peek() 会给你新的值。 - Michael Teper
@MichaelTeper 我知道我一年前发布了我的答案,但在我得到一些踩之后,我刚刚测试了它,它确实可以工作。请参见:http://jsfiddle.net/4MUWp/ - rjmunro
好的,我明白你做了什么......问题是关于在subscribe回调中检索值,这是无法使用peek()完成的。你的例子证明不了什么,反而可能会混淆新手。你基本上是在这里包装一个私有变量,并在设置之前显示其值-因此它当然不会改变。 - Simon_Weaver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接