Obtenha o valor anterior de um observável em subscrever o mesmo observável

86

É possível obter no knockout o valor atual de um observável dentro de uma assinatura desse observável, antes de receber o novo valor?

Exemplo:

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
fonte

Respostas:

88

Existe uma maneira de fazer uma assinatura do valor before desta forma:

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
fonte
o que thissignifica aqui?
Thanasis Ioannidis
152
ko.subscribable.fn.subscribeChanged = function (callback) {
    var oldValue;
    this.subscribe(function (_oldValue) {
        oldValue = _oldValue;
    }, this, 'beforeChange');

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

Use o acima assim:

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

});
JBeagle
fonte
2
relativamente novo no knockout, mas estou desejando que esta seja a forma como a assinatura padrão foi configurada. Ou .. este fn vai pelo menos coçar minha primeira coceira quando eu usar 'assinar' pela primeira vez.
bkwdesign
1
Houve algum movimento sobre isso em github.com/knockout/knockout/issues/914 . Parece que está previsto para o lançamento 3.4.
AlignedDev
2
No caso de o tipo de valor observável subscrito ser um Array, você deve dividi-lo, caso contrário, o oldValue será sempre o mesmo que o newValue. Verifique um exemplo funcional, aqui: jsfiddle.net/david_freire/xmk6u9yn/4
David Freire
1
Legal. Adicionado um valor de retorno que é um objeto de assinatura com uma dispose()função gist.github.com/30ff1f5c1adf215179b0046515f86e45
Michael
Oh, acabei de ver a conversa idiota.
Michael
21

Uma pequena mudança na resposta do Beagle90. Sempre retorne a própria assinatura para poder acessar o dispose (), por exemplo.

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
fonte
2
Este é um passo real, mas chamar .disposeo valor de retorno disso descartará apenas a segunda assinatura, não a 'beforeChange'assinatura
TRManderson
18

A solicitação pull para adicionar esse recurso tem algum código diferente que acaba sendo melhor do que depender do uso do beforeChangeevento.

Todo o crédito pela solução para 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 Michael:

Originalmente, sugeri usar beforeChangepara resolver esse problema, mas desde então percebi que nem sempre é confiável (por exemplo, se você chamar valueHasMutated()o observável).

James Johnson
fonte
3

Descobri que posso chamar peek () de um observável computado gravável para obter o valor anterior.

Algo assim (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
fonte
1
Isso não funciona, infelizmente, pois no momento em que o retorno de chamada de assinatura é chamado, o valor já mudou e, portanto peek(), fornecerá o novo valor.
Michael Teper
@MichaelTeper Sei que postei minha resposta há um ano, mas depois que recebi alguns votos negativos, acabei de testá-la e funciona. Veja: jsfiddle.net/4MUWp
rjmunro
Ok, vejo o que você fez aí ... A questão era sobre como recuperar o valor em um subscriberetorno de chamada que não pode ser feito com peek (). Seu exemplo não prova nada e pode confundir um recém-chegado. Você basicamente está encapsulando uma variável privada aqui e exibe seu valor antes de defini-la - então é claro que não terá mudado.
Simon_Weaver