Obtenga el valor anterior de un observable en la suscripción del mismo observable

85

¿Es posible en el nocaut obtener el valor actual de un observable dentro de una suscripción a ese observable, antes de que reciba el nuevo valor?

Ejemplo:

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
fuente

Respuestas:

88

Hay una forma de suscribirse al valor anterior como este:

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");
RP Niemeyer
fuente
¿Qué thissignifica aquí?
Thanasis Ioannidis
151
ko.subscribable.fn.subscribeChanged = function (callback) {
    var oldValue;
    this.subscribe(function (_oldValue) {
        oldValue = _oldValue;
    }, this, 'beforeChange');

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

Utilice lo anterior así:

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

});
JBeagle
fuente
2
bastante nuevo en knockout, pero deseo que esta sea la forma en que se configuró la suscripción predeterminada. O ... esta fn al menos rascará mi primera picazón ya que uso 'subscribe' por primera vez.
bkwdesign
1
Ha habido algún movimiento sobre esto en github.com/knockout/knockout/issues/914 . Parece que está programado para la versión 3.4.
Alineado el
2
En caso de que el tipo de valor observable suscrito sea un Array, debe dividirlo, de lo contrario, el oldValue siempre será el mismo que el newValue. Vea un ejemplo de trabajo, aquí: jsfiddle.net/david_freire/xmk6u9yn/4
David Freire
1
Frio. Se agregó un valor de retorno que es un objeto de suscripción con una dispose()función gist.github.com/30ff1f5c1adf215179b0046515f86e45
Michael
Oh, acabo de ver la conversación git.
Michael
21

Pequeños cambios en la respuesta de Beagle90. Devuelva siempre la propia suscripción para poder acceder a dispose (), por ejemplo.

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
fuente
1
Este es un verdadero paso adelante, pero solicitar .disposeel valor de retorno de esto solo eliminará la segunda suscripción, no la 'beforeChange'suscripción
TRManderson
18

La solicitud de extracción para agregar esta función tiene un código diferente que termina siendo mejor que confiar en el uso del beforeChangeevento.

Todo el mérito de la solución a 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);
    });
};

Para citar a Michael:

Originalmente sugerí usarlo beforeChangepara resolver este problema, pero desde entonces me he dado cuenta de que no siempre es confiable (por ejemplo, si llama valueHasMutated()al observable).

James Johnson
fuente
3

Descubrí que puedo llamar a peek () desde un observable calculado que se puede escribir para obtener el valor anterior.

Algo como esto (consulte 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
fuente
1
Desafortunadamente, eso no funciona, ya que cuando se llama a la devolución de llamada de suscripción, el valor ya cambió y, por peek()lo tanto, le dará el nuevo valor.
Michael Teper
@MichaelTeper Sé que publiqué mi respuesta hace un año, pero después de recibir algunos votos negativos, lo acabo de probar y funciona. Ver: jsfiddle.net/4MUWp
rjmunro
Ok, veo lo que hiciste allí ... La pregunta era sobre la recuperación del valor en una subscribedevolución de llamada que no se puede hacer con peek (). Su ejemplo no prueba nada y podría confundir a un recién llegado. Básicamente, está ajustando una variable privada aquí y muestra su valor antes de configurarla, por lo que, por supuesto, no habrá cambiado.
Simon_Weaver