81

给定一个计算属性

vm.checkedValueCount = ko.computed(function(){
  var observables = getCurrentValues();  //an array of ko.observable[]
  return _.filter(observables, function(v) { return v() }).length;
});

假设 getCurrentValues() 可以返回不同的 observable 集合,这些集合在代码的其他地方被修改(并且来自比 observableArray 更复杂的结构)。

我需要checkedValueCount随时更新

  • 它的依赖项之一发生了变化
  • getCurrentValues() 返回一组不同的 observables。

问题是它ko.computed似乎记住了最后一个返回的值,并且仅在依赖项更新时才更新。这处理第一种情况,但不处理后一种情况。

我正在寻找的是一种强制 checkValueCount 重新运行的方法。我可以使用的东西像:

changeCurrentValues();
vm.checkeValueCount.recalculate();

最简单地说,鉴于我有

a = ko.computed(function() { return Math.random() })

如何强制调用a()两次以返回不同的值。

4

5 回答 5

118

我意识到我的第一个答案错过了您的观点,并且不会解决您的问题。

问题是,如果有一些可观察的迫使它重新评估,那么计算只会重新评估。没有本地方法可以强制计算重新评估。

但是,您可以通过创建一个虚拟的可观察值然后告诉它的订阅者它已经改变来解决这个问题。

(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());

}());​

这是一个展示这种方法的小提琴

于 2012-12-07T19:41:25.900 回答
8

一种方法可以根据您的情况强制重新计算所有可观察量:

getCurrentValues.valueHasMutated()
于 2014-11-10T18:42:26.243 回答
4

这个答案在概念上与@josh 给出的答案相同,但呈现为更通用的包装器。注意:此版本适用于“可写”计算。

我正在使用 Typescript,所以我首先包含了 ts.d 定义。因此,如果与您无关,请忽略第一部分。

interface KnockoutStatic
{
    notifyingWritableComputed<T>(options: KnockoutComputedDefine<T>, context ?: any): KnockoutComputed<T>;
}

通知可写计算

一个可写的包装器,observable总是会通知订阅者——即使write调用后没有更新任何可观察的对象

如果您不使用 Typescript ,只需替换function<T> (options: KnockoutComputedDefine<T>, context)为。function(options, 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函数“访问”的可观察对象的更改时。

例如,我正在使用 LocalStorage 设置一些值,但没有任何可观察到的变化来触发重新评估。

hasUserClickedFooButton = ko.notifyingWritableComputed(
{
    read: () => 
    {
        return LocalStorageHelper.getBoolValue('hasUserClickedFooButton');
    },
    write: (v) => 
    {
        LocalStorageHelper.setBoolValue('hasUserClickedFooButton', v);        
    }
});

请注意,我只需要更改ko.computedko.notifyingWritableComputed然后一切都会自行处理。

当我调用时hasUserClickedFooButton(true),'dummy' observable 会增加,强制任何订阅者(及其订阅者)在 LocalStorage 中的值更新时获取新值。

(注意:您可能认为notify: 'always'扩展器是这里的一个选项 - 但这是不同的)。


对于只可读的计算 observable 有一个额外的解决方案:

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();

来自@mbest 评论https://github.com/knockout/knockout/issues/1019

于 2015-04-30T05:57:43.390 回答
1

假设 getCurrentValues() 可以返回不同的可观察对象集,这些可观察对象集在代码的其他地方被修改

我假设 getCurrentValues() 是一个函数。如果您可以将其设为计算值,那么您的 checkedValueCount 就会神奇地开始工作。

你能让 getCurrentValues 成为一个计算值而不是一个函数吗?

于 2012-12-07T19:26:52.027 回答
0

因为没有直接的方法来强制更新一个计算,我创建了一个名为 toForceComputedUpdate 的 observable,我在计算函数中调用它,所以计算将监听它的更新,然后强制更新我这样调用它 toForceComputedUpdate(Math 。随机的)

于 2016-11-21T22:40:41.110 回答