Holen Sie sich den vorherigen Wert eines Observable in abonnieren Sie dasselbe Observable

85

Ist es beim Knockout möglich, den aktuellen Wert eines Observable innerhalb eines Abonnements für dieses Observable abzurufen, bevor es den neuen Wert erhält?

Beispiel:

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
quelle

Antworten:

88

Es gibt eine Möglichkeit, den vorherigen Wert wie folgt zu abonnieren:

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
quelle
Wofür thissteht hier?
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);
    });
};

Verwenden Sie das oben genannte wie folgt:

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

});
JBeagle
quelle
2
ziemlich neu im Knockout, aber ich wünschte, dies wäre die Art und Weise, wie das Standardabonnement eingerichtet wurde. Oder .. dieses fn kratzt zumindest meinen ersten Juckreiz, wenn ich zum ersten Mal 'subscribe' benutze.
bkwdesign
1
Diesbezüglich hat sich etwas bewegt github.com/knockout/knockout/issues/914 . Sieht so aus, als wäre es für die Version 3.4 geplant.
Ausgerichtet
2
Wenn der abonnierte beobachtbare Werttyp ein Array ist, müssen Sie ihn in Scheiben schneiden, andernfalls ist der alte Wert immer der gleiche wie der neue Wert. Überprüfen Sie hier ein funktionierendes Beispiel: jsfiddle.net/david_freire/xmk6u9yn/4
David Freire
1
Cool. Es wurde ein Rückgabewert hinzugefügt, bei dem es sich um ein Abonnementobjekt mit der dispose()Funktion gist.github.com/30ff1f5c1adf215179b0046515f86e45 handelt
Michael
Oh, ich habe gerade das Git-Gespräch gesehen.
Michael
21

Kleine Änderung an Beagle90 Antwort. Geben Sie das Abonnement immer selbst zurück, um beispielsweise auf dispose () zugreifen zu können.

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
quelle
1
Dies ist ein echter Schritt nach oben, aber wenn Sie .disposeden Rückgabewert daraus aufrufen, wird nur das zweite Abonnement entsorgt, nicht das 'beforeChange'Abonnement
TRManderson
18

Die Pull-Anforderung zum Hinzufügen dieser Funktion enthält einen anderen Code, der besser ist als die Verwendung des beforeChangeEreignisses.

Alle Ehre für die Lösung an 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);
    });
};

Um Michael zu zitieren:

Ich habe ursprünglich vorgeschlagen beforeChange, dieses Problem zu lösen, habe aber inzwischen festgestellt, dass es nicht immer zuverlässig ist (zum Beispiel, wenn Sie valueHasMutated()das Observable aufrufen ).

James Johnson
quelle
3

Ich habe festgestellt, dass ich peek () von einem beschreibbaren berechneten Observable aus aufrufen kann, um den Vorher-Wert zu erhalten.

So etwas (siehe 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
quelle
1
Das funktioniert leider nicht, da sich der Wert zum Zeitpunkt des Aufrufs des Abonnement-Rückrufs bereits geändert hat und peek()Sie den neuen Wert erhalten.
Michael Teper
@MichaelTeper Ich weiß, dass ich meine Antwort vor einem Jahr gepostet habe, aber nachdem ich einige Abstimmungen erhalten habe, habe ich sie gerade getestet und sie funktioniert. Siehe: jsfiddle.net/4MUWp
rjmunro
Ok, ich verstehe, was Sie dort getan haben ... Die Frage war, den Wert in einem subscribeRückruf abzurufen , was mit peek () nicht möglich ist. Ihr Beispiel beweist nichts und könnte einen Neuling verwirren. Grundsätzlich verpacken Sie hier eine private Variable und zeigen ihren Wert an, bevor Sie sie festlegen - natürlich hat sich nichts daran geändert.
Simon_Weaver