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

85

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

Пример:

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
});
KodeKreachor
источник

Ответы:

88

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

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означает?
Танасис Иоаннидис,
151
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) {

});
JBeagle
источник
2
довольно новичок в нокауте, но я бы хотел, чтобы подписка по умолчанию была настроена именно так. Или .. эта fn, по крайней мере, избавит меня от первого зуда, когда я впервые использую «подписаться».
bkwdesign 08
1
На github.com/knockout/knockout/issues/914 по этому поводу произошли некоторые подвижки . Похоже, он выйдет в версии 3.4.
Согласовано
2
В случае, если подписанный наблюдаемый тип значения является массивом, вы должны разрезать его, иначе oldValue всегда будет таким же, как newValue. Проверьте рабочий пример здесь: jsfiddle.net/david_freire/xmk6u9yn/4
Дэвид Фрейре,
1
Круто. Добавлено возвращаемое значение, являющееся объектом подписки, с dispose()функцией gist.github.com/30ff1f5c1adf215179b0046515f86e45
Майкл
Ой, только что видел этот мерзкий разговор.
Michael
21

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

В запросе на добавление этой функции есть другой код, который оказывается лучше, чем полагаться на использование 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()наблюдаемое).

Джеймс Джонсон
источник
3

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