Gegeben eine berechnete Eigenschaft
vm.checkedValueCount = ko.computed(function(){
var observables = getCurrentValues(); //an array of ko.observable[]
return _.filter(observables, function(v) { return v() }).length;
});
Angenommen, getCurrentValues () kann verschiedene Sätze von Observablen zurückgeben, die an anderer Stelle im Code geändert wurden (und aus einer komplexeren Struktur stammen als ein ObservableArray).
Ich muss checkedValueCount
jederzeit aktualisieren
- Eine seiner Abhängigkeiten ändert sich
- getCurrentValues () gibt einen anderen Satz von Observablen zurück.
Das Problem ist, dass ko.computed
der zuletzt zurückgegebene Wert scheinbar gespeichert und nur aktualisiert wird, wenn eine Abhängigkeit aktualisiert wird. Dies behandelt den ersten Fall, nicht jedoch den letzteren.
Was ich suche, ist eine Möglichkeit, checkedValueCount zur erneuten Ausführung zu zwingen. Etwas, das ich verwenden kann wie:
changeCurrentValues();
vm.checkeValueCount.recalculate();
Einfach gesagt, vorausgesetzt, ich habe
a = ko.computed(function() { return Math.random() })
Wie kann ich das a()
zweimalige Aufrufen erzwingen , um unterschiedliche Werte zurückzugeben?
quelle
Antworten:
Ich habe festgestellt, dass meine erste Antwort Ihren Standpunkt verfehlt hat und Ihr Problem nicht lösen wird.
Das Problem ist, dass ein berechneter Wert nur dann neu bewertet wird, wenn ein beobachtbarer Wert vorhanden ist, der ihn zur Neubewertung zwingt. Es gibt keine native Möglichkeit, einen Computer zur Neubewertung zu zwingen.
Sie können dies jedoch mit etwas Hackery umgehen, indem Sie einen beobachtbaren Dummy-Wert erstellen und dann seinen Abonnenten mitteilen, dass er sich geändert hat.
(function() { var vm = function() { var $this = this; $this.dummy = ko.observable(); $this.curDate = ko.computed(function() { $this.dummy(); return new Date(); }); $this.recalcCurDate = function() { $this.dummy.notifySubscribers(); }; }; ko.applyBindings(new vm()); }());
Hier ist eine Geige, die diesen Ansatz zeigt
quelle
Es gibt eine Methode , um die Neuberechnung aller Observablen abhängig von Ihrer zu erzwingen:
quelle
getCurrentValues(); //an array of ko.observable[]
valueHasMutated
Methode auf. Das unterscheidet sich nicht wirklich grundlegend von Joshs Antwort oben, oder? Tatsächlich zwingt es Sie zu wissen, worauf verwiesen wird, und zu wissen, dass diese Referenzen beobachtbar (und nicht berechnet) sind.Diese Antwort ist konzeptionell dieselbe wie die von @josh, wird jedoch als allgemeinerer Wrapper dargestellt. Hinweis: Diese Version ist für eine 'beschreibbare' Berechnung.
Ich verwende Typescript, daher habe ich zuerst die ts.d-Definition eingefügt. Ignorieren Sie diesen ersten Teil, wenn er für Sie nicht relevant ist.
Benachrichtigung-beschreibbar-berechnet
Ein Wrapper für eine beschreibbare Datei
observable
, der immer dazu führt, dass Abonnenten benachrichtigt werden - auch wenn infolge deswrite
Aufrufs keine Observables aktualisiert wurdenErsetzen Sie einfach
function<T> (options: KnockoutComputedDefine<T>, context)
mit ,function(options, context)
wenn Sie nicht Typoskript verwenden.ko.notifyingWritableComputed = function<T> (options: KnockoutComputedDefine<T>, context) { var _notifyTrigger = ko.observable(0); var originalRead = options.read; var originalWrite = options.write; // intercept 'read' function provided in options options.read = () => { // read the dummy observable, which if updated will // force subscribers to receive the new value _notifyTrigger(); return originalRead(); }; // intercept 'write' function options.write = (v) => { // run logic provided by user originalWrite(v); // force reevaluation of the notifyingWritableComputed // after we have called the original write logic _notifyTrigger(_notifyTrigger() + 1); }; // just create computed as normal with all the standard parameters return ko.computed(options, context); }
Der Hauptanwendungsfall hierfür ist, wenn Sie etwas aktualisieren, das sonst keine Änderung in einem Observable auslösen würde, das von der
read
Funktion "besucht" wird .Zum Beispiel verwende ich LocalStorage, um einige Werte festzulegen, aber es gibt keine Änderung an beobachtbaren Werten, um eine Neubewertung auszulösen.
hasUserClickedFooButton = ko.notifyingWritableComputed( { read: () => { return LocalStorageHelper.getBoolValue('hasUserClickedFooButton'); }, write: (v) => { LocalStorageHelper.setBoolValue('hasUserClickedFooButton', v); } });
Beachten Sie, dass alles , was ich brauchte , war Änderung
ko.computed
zuko.notifyingWritableComputed
und dann alles kümmert sich um sich selbst.Wenn ich
hasUserClickedFooButton(true)
anrufe, wird die beobachtbare "Dummy" erhöht, wodurch alle Abonnenten (und ihre Abonnenten) gezwungen werden, den neuen Wert zu erhalten, wenn der Wert in LocalStorage aktualisiert wird.(Hinweis: Sie denken vielleicht, dass der
notify: 'always'
Extender hier eine Option ist - aber das ist etwas anderes).Es gibt eine zusätzliche Lösung für ein berechnetes Observable, das nur lesbar ist:
ko.forcibleComputed = function(readFunc, context, options) { var trigger = ko.observable().extend({notify:'always'}), target = ko.computed(function() { trigger(); return readFunc.call(context); }, null, options); target.evaluateImmediate = function() { trigger.valueHasMutated(); }; return target; }; myValue.evaluateImmediate();
Von @mbest Kommentar https://github.com/knockout/knockout/issues/1019 .
quelle
Ich gehe davon aus, dass getCurrentValues () eine Funktion ist. Wenn Sie es zu einem berechneten Wert machen könnten, würde Ihr checkedValueCount auf magische Weise funktionieren.
Können Sie getCurrentValues als berechnete Funktion anstelle einer Funktion festlegen?
quelle
Da es keine einfache Möglichkeit gibt, die Aktualisierung eines berechneten Datums zu erzwingen, habe ich ein Observable mit dem Namen toForceComputedUpdate erstellt und es innerhalb der berechneten Funktion aufgerufen, damit das berechnete Update das Update abhört. Um das Update zu erzwingen, nenne ich es so toForceComputedUpdate (Math .zufällig)
quelle