强制运行计算属性函数

时间:2012-12-07 19:08:06

标签: knockout.js computed-observable

给定计算属性

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()返回一组不同的observable。

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

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

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

最简单的说,因为我有

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

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

5 个答案:

答案 0 :(得分:111)

我意识到我的第一个回答错过了你的观点,并且无法解决你的问题。

问题是计算机只会重新评估是否存在一些强制它重新评估的可观察量。没有本地方法强制计算机重新评估。

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

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

}());​

Here is a Fiddle显示了这种方法

答案 1 :(得分:8)

a method强制重新计算所有可观察量,具体取决于你的:

getCurrentValues.valueHasMutated()

答案 2 :(得分: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设置一些值,但是任何observable都没有变化来触发重新评估。

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

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

当我致电hasUserClickedFooButton(true)时,我会打电话给“{1}}&#39;当LocalStorage中的值更新时,observable会递增,强制任何订阅者(及其订阅者)获取新值。

(注意:您可能认为此处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

答案 3 :(得分:1)

  

假设getCurrentValues()可以返回不同的observable集   在代码的其他地方修改了

我假设getCurrentValues()是一个函数。如果你可以使它成为计算机,那么你的checkedValueCount就会神奇地开始工作。

你可以让getCurrentValues成为计算而不是函数吗?

答案 4 :(得分:-1)

由于没有直接强制更新计算机的方法,我创建了一个名为toForceComputedUpdate的observable,并且我在计算函数内调用它,因此计算机将监听其更新,然后强制更新我称之为像这样toForceComputedUpdate(的Math.random)