Получить предыдущее значение наблюдаемого в подписке на тот же наблюдаемый

Возможно ли в нокауте получить текущее значение наблюдаемого в подписке на этот наблюдаемый объект до того, как он получит новое значение?

Пример:

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
});

person KodeKreachor    schedule 10.10.2012    source источник


Ответы (5)


Есть способ сделать подписку на предыдущее значение следующим образом:

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");
person RP Niemeyer    schedule 10.10.2012
comment
что здесь означает this? - person Thanasis Ioannidis; 19.06.2020
comment
@ThanasisIoannidis Это гарантирует, что вы можете получить доступ к тому же значению this внутри функции обратного вызова. В противном случае вам нужно будет заранее сохранить его под другим именем, например var self = this; (что тоже является вполне действенной стратегией). - person marcus; 14.07.2021

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) {

});
person JBeagle    schedule 12.08.2013
comment
довольно новичок в нокауте, но я бы хотел, чтобы подписка по умолчанию была настроена именно так. Или .. эта fn по крайней мере почесает мою первую боль, когда я впервые использую «подписаться». - person bkwdesign; 09.11.2013
comment
На github.com/knockout/knockout/issues/914. Похоже, он выйдет в версии 3.4. - person AlignedDev; 25.09.2015
comment
В случае, если подписанный наблюдаемый тип значения является массивом, вы должны разрезать его, иначе oldValue всегда будет таким же, как newValue. Проверьте рабочий пример здесь: jsfiddle.net/david_freire/xmk6u9yn/4 - person David Freire; 30.09.2015
comment
Прохладный. Добавлено возвращаемое значение, которое является объектом подписки с функцией dispose() gist.github.com/30ff1f5c1adf215179b0046515f86e45 - person Michael; 20.07.2016
comment
Ой, только что видел этот мерзкий разговор. - person Michael; 20.07.2016
comment
@DavidFreire, если массив содержит объекты, он все еще сломан. Я пытался обойти это, это довольно грязно. В конце концов, я добавил дополнительную подписку, которая полностью обрабатывает значение как JSON. - person br4nnigan; 14.04.2020

Небольшое изменение в ответе 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;
};
person Andries    schedule 22.12.2014
comment
Это реальный шаг вперед, но вызов .dispose для возвращаемого значения приведет к удалению только второй подписки, а не 'beforeChange' подписки. - person TRManderson; 31.01.2019

pull request для добавления этой функции содержит другой код, который оказывается лучше, чем полагаться на использование события beforeChange.

Вся благодарность за решение Майклу Бесту

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

Процитирую Майкла:

Первоначально я предлагал использовать beforeChange для решения этой проблемы, но с тех пор понял, что это не всегда надежно (например, если вы вызываете valueHasMutated() для наблюдаемого).

person James Johnson    schedule 05.03.2015

Я обнаружил, что могу вызвать 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);
    }
});
person rjmunro    schedule 08.04.2013
comment
К сожалению, это не работает, поскольку к моменту вызова обратного вызова подписки значение уже изменилось, и peek() предоставит вам новое значение. - person Michael Teper; 18.01.2014
comment
@MichaelTeper Я знаю, что опубликовал свой ответ год назад, но после того, как я получил несколько голосов против, я только что протестировал его, и он действительно работает. См .: jsfiddle.net/4MUWp - person rjmunro; 30.07.2014
comment
Хорошо, я вижу, что вы там сделали ... Вопрос касался получения значения в обратном вызове subscribe, что невозможно сделать с помощью peek (). Ваш пример ничего не доказывает и может запутать новичка. По сути, вы обертываете здесь частную переменную и отображаете ее значение перед ее установкой - так что, конечно, оно не изменится. - person Simon_Weaver; 06.02.2015