Esta respuesta es conceptualmente la misma que la que dio @josh, pero presentada como una envoltura más genérica. Nota: esta versión es para un cálculo "escribible".
Estoy usando TypeScript, así que incluí primero la definición ts.d. Así que ignore esta primera parte si no es relevante para usted.
interface KnockoutStatic
{
notifyingWritableComputed<T>(options: KnockoutComputedDefine<T>, context ?: any): KnockoutComputed<T>;
}
Notificando-escribible-calculado
Un contenedor para una escritura observable
que siempre hace que los suscriptores sean notificados, incluso si no se actualizaron observables como resultado de la write
llamada.
Simplemente reemplácelo function<T> (options: KnockoutComputedDefine<T>, context)
con function(options, context)
si no usa Typecript.
ko.notifyingWritableComputed = function<T> (options: KnockoutComputedDefine<T>, context)
{
var _notifyTrigger = ko.observable(0);
var originalRead = options.read;
var originalWrite = options.write;
options.read = () =>
{
_notifyTrigger();
return originalRead();
};
options.write = (v) =>
{
originalWrite(v);
_notifyTrigger(_notifyTrigger() + 1);
};
return ko.computed(options, context);
}
El caso de uso principal para esto es cuando está actualizando algo que de otra manera no desencadenaría un cambio en un observable que es 'visitado' por la read
función.
Por ejemplo, estoy usando LocalStorage para establecer algunos valores, pero no hay ningún cambio en ningún observable para activar la reevaluación.
hasUserClickedFooButton = ko.notifyingWritableComputed(
{
read: () =>
{
return LocalStorageHelper.getBoolValue('hasUserClickedFooButton');
},
write: (v) =>
{
LocalStorageHelper.setBoolValue('hasUserClickedFooButton', v);
}
});
Tenga en cuenta que todo lo que necesitaba era un cambio ko.computed
de ko.notifyingWritableComputed
y entonces todo se cuida solo.
Cuando llamo hasUserClickedFooButton(true)
, el observable 'ficticio' se incrementa, lo que obliga a los suscriptores (y sus suscriptores) a obtener el nuevo valor cuando se actualiza el valor en LocalStorage.
(Nota: puede pensar que el notify: 'always'
extensor es una opción aquí, pero eso es algo diferente).
Existe una solución adicional para un observable calculado que solo se puede leer:
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();
Del comentario de @mbest https://github.com/knockout/knockout/issues/1019 .