强制计算属性函数运行
给定一个计算的属性
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
似乎memoize最后返回的值,只有更新时,依赖项更新。 这处理第一个案件,但不是后者。
我正在寻找的方法是强制checkedValueCount重新运行。 一些我可以使用的东西:
changeCurrentValues(); vm.checkeValueCount.recalculate();
最简单的,因为我有
a = ko.computed(function() { return Math.random() })
我怎么能强制调用a()
两次返回不同的值。
我意识到我的第一个答案错过了你的观点,并不会解决你的问题。
问题是如果有一些可观察的结果迫使它重新评估,计算结果将只会重新评估。 没有原生的方法来强制计算重新评估。
然而,你可以通过创build一个虚拟的可观察值,然后告诉它的订阅者它已经改变来解决这个问题。
(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
调用而被更新
如果不使用Typescript,只需要用function(options, context)
replacefunction<T> (options: KnockoutComputedDefine<T>, context)
。
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); }
主要的用例是当你更新一些不会触发read
函数“访问”的observable的变化时。
例如,我使用LocalStorage来设置一些值,但没有任何可观察到的变化来触发重新评估。
hasUserClickedFooButton = ko.notifyingWritableComputed( { read: () => { return LocalStorageHelper.getBoolValue('hasUserClickedFooButton'); }, write: (v) => { LocalStorageHelper.setBoolValue('hasUserClickedFooButton', v); } });
请注意,所有我需要改变ko.computed
为ko.notifyingWritableComputed
,然后一切照顾自己。
当我调用hasUserClickedFooButton(true)
那么'dummy'可观察值将增加,迫使任何订阅者(及其订阅者)在LocalStorage中的值更新时获取新值。
(注意:你可能会认为notify: 'always'
扩展是这里的一个选项 – 但这是不同的)。
有一个额外的解决scheme,只有可读的计算观察值:
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();
假设getCurrentValues()可以返回在代码中其他地方修改过的不同的可观察集合
我假设getCurrentValues()是一个函数。 如果你可以使它成为一个计算,你的checkedValueCount会神奇地开始工作。
你可以让getCurrentValues是一个计算而不是一个函数?
因为没有直接的方法来强制更新计算,我已经创build了一个名为toForceComputedUpdate的可观察值,我在计算函数内调用它,所以计算将监听它的更新,然后强制更新我像这样调用它toForceComputedUpdate(Math 。随机)