Étant donné une propriété calculée
vm.checkedValueCount = ko.computed(function(){
var observables = getCurrentValues(); //an array of ko.observable[]
return _.filter(observables, function(v) { return v() }).length;
});
supposons que getCurrentValues () peut renvoyer différents ensembles d'observables qui sont modifiés ailleurs dans le code (et proviennent d'une structure plus complexe qu'un observableArray).
J'ai besoin de checkedValueCount
pour mettre à jour chaque fois
Le problème est que ko.computed
Semble mémoriser la dernière valeur retournée et ne se mettre à jour que lorsqu'une dépendance est mise à jour. Cela gère le premier cas mais pas le dernier.
Ce que je recherche, c'est un moyen de forcer checkValueCount à se réexécuter. Quelque chose que je peux utiliser comme:
changeCurrentValues();
vm.checkeValueCount.recalculate();
En termes plus simples, étant donné que j'ai
a = ko.computed(function() { return Math.random() })
comment puis-je forcer l'invocation de a()
deux fois pour retourner des valeurs différentes.
J'ai réalisé que ma première réponse a manqué votre point et ne résoudra pas votre problème.
Le problème est qu'un calcul ne sera réévalué que s'il existe des éléments observables qui l'obligent à réévaluer. Il n'existe aucun moyen natif de forcer un calcul à réévaluer.
Cependant, vous pouvez contourner ce problème avec du piratage en créant une valeur factice observable, puis en indiquant à ses abonnés qu'elle a changé.
(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());
}());
Voici un violon montrant cette approche
Il y a ne méthode pour forcer le recalcul de tous les observables en fonction du vôtre:
getCurrentValues.valueHasMutated()
Cette réponse est conceptuellement la même que celle donnée par @josh, mais présentée comme un wrapper plus générique. Remarque: cette version est destinée à un calcul "inscriptible".
J'utilise TypeScript, j'ai donc inclus la définition ts.d en premier. Ignorez donc cette première partie si elle ne vous concerne pas.
interface KnockoutStatic
{
notifyingWritableComputed<T>(options: KnockoutComputedDefine<T>, context ?: any): KnockoutComputed<T>;
}
observable
inscriptible qui toujours oblige les abonnés à être notifiés - même si aucun observable n'a été mis à jour à la suite du write
appelRemplacez simplement function<T> (options: KnockoutComputedDefine<T>, context)
par function(options, context)
si vous n'utilisez pas TypeScript.
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);
}
Le cas d'utilisation principal pour cela est lorsque vous mettez à jour quelque chose qui ne déclencherait pas autrement un changement dans un observable qui est "visité" par la fonction read
.
Par exemple, j'utilise LocalStorage pour définir certaines valeurs, mais aucun changement n'est observable pour déclencher une réévaluation.
hasUserClickedFooButton = ko.notifyingWritableComputed(
{
read: () =>
{
return LocalStorageHelper.getBoolValue('hasUserClickedFooButton');
},
write: (v) =>
{
LocalStorageHelper.setBoolValue('hasUserClickedFooButton', v);
}
});
Notez que tout ce que je devais changer était ko.computed
En ko.notifyingWritableComputed
Et puis tout se prend en charge.
Lorsque j'appelle hasUserClickedFooButton(true)
alors l'observable "factice" est incrémenté forçant tous les abonnés (et leurs abonnés) à obtenir la nouvelle valeur lorsque la valeur dans LocalStorage est mise à jour.
(Remarque: vous pouvez penser que l'extension notify: 'always'
Est une option ici - mais c'est quelque chose de différent).
Il existe une solution supplémentaire pour un observable calculé qui n'est que lisible:
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();
D'après le commentaire @mbest https://github.com/knockout/knockout/issues/1019 .
supposons que getCurrentValues () peut renvoyer différents ensembles d'observables qui sont modifiés ailleurs dans le code
Je suppose que getCurrentValues () est une fonction. Si vous pouviez en faire un calcul, votre vérifiéValueCount commencerait tout simplement par magie.
Pouvez-vous faire de getCurrentValues un calcul au lieu d'une fonction?