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 Mengen von Observablen zurückgeben, die an anderer Stelle im Code geändert wurden (und aus einer komplexeren Struktur als observableArray stammen).
Ich brauche checkedValueCount
, um zu aktualisieren, wann immer
Das Problem ist, dass ko.computed
Sich den zuletzt zurückgegebenen Wert zu merken scheint und nur aktualisiert wird, wenn eine Abhängigkeit aktualisiert wird. Dies behandelt den ersten Fall, aber nicht den letzteren.
Was ich suche, ist eine Möglichkeit, checkedValueCount zum erneuten Ausführen zu zwingen. Etwas was ich benutzen kann wie:
changeCurrentValues();
vm.checkeValueCount.recalculate();
Am einfachsten ausgedrückt, vorausgesetzt, ich habe
a = ko.computed(function() { return Math.random() })
wie kann ich den zweimaligen Aufruf von a()
erzwingen, um unterschiedliche Werte zurückzugeben?.
Ich habe festgestellt, dass meine erste Antwort Ihren Standpunkt verfehlt hat und ich werde Ihr Problem nicht lösen.
Das Problem ist, dass ein berechneter Wert nur dann neu bewertet wird, wenn es einige beobachtbare Werte gibt, die ihn zur Neubewertung zwingen. Es gibt keine systemeigene Möglichkeit, einen Computer zur Neubewertung zu zwingen.
Sie können dieses Problem jedoch umgehen, indem Sie einen beobachtbaren Dummy-Wert erstellen und dann den Abonnenten mitteilen, dass er geändert wurde.
(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 zeigt diesen Ansatz
Es gibt eine Methode um die Neuberechnung aller Observablen zu erzwingen, abhängig von Ihrer:
getCurrentValues.valueHasMutated()
Diese Antwort ist konzeptionell dieselbe wie die von @josh, wird jedoch als allgemeinerer Wrapper dargestellt. Hinweis: Diese Version ist für ein 'beschreibbares' Gerät berechnet.
Da ich TypeScript verwende, habe ich zuerst die ts.d-Definition eingefügt. Ignorieren Sie diesen ersten Teil, wenn er für Sie nicht relevant ist.
interface KnockoutStatic
{
notifyingWritableComputed<T>(options: KnockoutComputedDefine<T>, context ?: any): KnockoutComputed<T>;
}
observable
, der immer dazu führt, dass Abonnenten benachrichtigt werden - selbst wenn infolge des Aufrufs von write
keine Observables aktualisiert wurdenErsetzen Sie einfach function<T> (options: KnockoutComputedDefine<T>, context)
durch function(options, context)
, wenn Sie TypeScript nicht 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 ansonsten keine Änderung in einer Beobachtungsdatei auslösen würde, die von der Funktion read
'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 ich nur ko.computed
In ko.notifyingWritableComputed
Ändern musste und dann alles für sich selbst sorgt.
Wenn ich hasUserClickedFooButton(true)
aufrufe, wird die beobachtbare 'Dummy'-Variable inkrementiert, sodass alle Abonnenten (und deren Abonnenten) gezwungen werden, den neuen Wert abzurufen, wenn der Wert in LocalStorage aktualisiert wird.
(Hinweis: Möglicherweise ist der Extender notify: 'always'
Hier eine Option - 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 .
angenommen, getCurrentValues () kann verschiedene Mengen von Observablen zurückgeben, die an anderer Stelle im Code geändert wurden
Ich nehme an, getCurrentValues () ist eine Funktion. Wenn Sie es zu einem berechneten Wert machen könnten, würde Ihr checkedValueCount auf magische Weise funktionieren.
Können Sie getCurrentValues anstelle einer Funktion berechnen lassen?