Принудительно запустить вычисляемую функцию свойства
учитывая вычисленное свойство
vm.checkedValueCount = ko.computed(function(){
var observables = getCurrentValues(); //an array of ko.observable[]
return _.filter(observables, function(v) { return v() }).length;
});
предположим, что getCurrentValues () может возвращать различные наборы наблюдаемых объектов, которые изменяются в другом месте кода (и происходят из более сложной структуры, чем observableArray).
мне нужно checkedValueCount
для обновления всякий раз, когда
- одна из его зависимостей меняется
- getCurrentValues () возвращает другой набор наблюдаемых.
проблема в том, что ko.computed
кажется, запомните последнее возвращенное значение и обновляйте только при обновлении зависимости. Это касается первого случая, но не последнего.
то, что я ищу, это способ заставить checkedValueCount повторно запустить. То, что я могу использовать такие как:
changeCurrentValues();
vm.checkeValueCount.recalculate();
проще говоря, учитывая, что у меня
a = ko.computed(function() { return Math.random() })
как я могу принудительно вызвать a()
дважды для возврата различных значений.
5 ответов:
Я понял, что мой первый ответ пропустил вашу точку зрения и не решит вашу проблему.
проблема в том, что вычисленный будет переоценивать только если есть некоторые наблюдаемые, которые заставляют его переоценивать. Нет никакого собственного способа заставить вычисленный повторно оценить.
однако вы можете обойти это с помощью некоторого хакерства, создав фиктивное наблюдаемое значение, а затем сообщив своим подписчикам, что оно изменилось.
(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()); }());
здесь-это скрипка показывает такой подход
здесь метод чтобы заставить пересчет всех наблюдаемых в зависимости от вашего:
getCurrentValues.valueHasMutated()
этот ответ концептуально совпадает с тем, который дал @josh, но представлен как более общая оболочка. Примечание: эта версия предназначена для записи вычисляемых.
я использую Typescript, поэтому я включил ts.D определение первого. Поэтому игнорируйте эту первую часть, если она не имеет к вам отношения.
interface KnockoutStatic { notifyingWritableComputed<T>(options: KnockoutComputedDefine<T>, context ?: any): KnockoutComputed<T>; }
уведомления-записи-компьютерная
обертка для записи
observable
это всегда вызывает абонента уведомление-даже если никакие наблюдаемые не были обновлены в результатеwrite
вызовпросто заменить
function<T> (options: KnockoutComputedDefine<T>, context)
Сfunction(options, context)
если вы не используете 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); }
основной вариант использования для этого - когда вы обновляете что-то, что в противном случае не вызвало бы изменения в наблюдаемом, которое "посещается".
например, я использую LocalStorage для установки некоторых значений, но нет никаких изменений для любого наблюдаемого триггера переоценка.
hasUserClickedFooButton = ko.notifyingWritableComputed( { read: () => { return LocalStorageHelper.getBoolValue('hasUserClickedFooButton'); }, write: (v) => { LocalStorageHelper.setBoolValue('hasUserClickedFooButton', v); } });
обратите внимание, что все, что мне нужно изменить в
ko.computed
доko.notifyingWritableComputed
и тогда все произойдет само собой.когда я называю
hasUserClickedFooButton(true)
затем "фиктивный" наблюдаемый увеличивается, заставляя всех подписчиков (и их подписчиков) получать новое значение при обновлении значения в LocalStorage.(Примечание: Вы можете думать
notify: 'always'
расширитель-это вариант здесь, но это что-то другое).
есть дополнительное решение для вычисленного наблюдаемого, которое только читается:
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();
из комментария @mbesthttps://github.com/knockout/knockout/issues/1019.
предположим, что getCurrentValues () может возвращать различные наборы наблюдаемых которые изменяются в другом месте кода
Я предполагаю, что getCurrentValues () является функцией. Если бы вы могли сделать его вычисленным, ваш checkedValueCount просто волшебным образом начнет работать.
вы можете сделать getCurrentValues быть вычисляемым, а не функция?