web-dev-qa-db-ja.com

計算されたプロパティ関数を強制的に実行する

計算されたプロパティを考える

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

getCurrentValues()が、コード内の他の場所で変更された(およびobservableArrayよりも複雑な構造に由来する)オブザーバブルの異なるセットを返すことができると仮定します。

常に更新するにはcheckedValueCountが必要です

  • 依存関係の変更の1つ
  • getCurrentValues()は、異なるオブザーバブルのセットを返します。

問題は、_ko.computed_が最後に返された値をメモし、依存関係が更新されたときにのみ更新されるように見えることです。これは最初のケースを処理しますが、後者は処理しません。

私が探しているのは、checkedValueCountを強制的に再実行する方法です。私が使用できるもの:

_changeCurrentValues();
vm.checkeValueCount.recalculate();
_

私が持っていることを考えると、最も簡単に言えば

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

a()を2回呼び出して異なる値を返すにはどうすればよいですか。

77
George Mauer

私の最初の答えがあなたの主張を逃し、あなたの問題を解決できないことに気づきました。

問題は、再評価を強制する観察可能なものがある場合にのみ、計算されたものが再評価されることです。計算されたものを強制的に再評価するネイティブな方法はありません。

ただし、ダミーの観測可能な値を作成し、サブスクライバーに値が変更されたことを伝えることで、いくつかのハッカーでこれを回避できます。

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

}());​

これはフィドルです このアプローチを示しています

113
Josh

メソッド があり、あなたに応じてすべてのオブザーバブルの再計算を強制します:

getCurrentValues.valueHasMutated()
8
Rustam

この答えは概念的には@joshが与えたものと同じですが、より一般的なラッパーとして提示されます。注:このバージョンは、「書き込み可能」計算用です。

TypeScriptを使用しているため、最初にts.d定義を含めました。関係ない場合は、この最初の部分を無視してください。

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


通知-書き込み可能-計算済み

alwaysが常に通知されるようにする書き込み可能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.computed_から_ko.notifyingWritableComputed_であり、すべてが自分で処理することに注意してください。

hasUserClickedFooButton(true)を呼び出すと、 'ダミー'オブザーバブルがインクリメントされ、LocalStorageの値が更新されたときにすべてのサブスクライバー(およびそのサブスクライバー)に新しい値を強制的に取得させます。

(注:ここでは_notify: 'always'_エクステンダーがオプションであると思われるかもしれません-しかし、それは別のものです)。


Readbleのみである計算されたオブザーバブルには、追加のソリューションがあります。

_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

4
Simon_Weaver

getCurrentValues()がコードの他の場所で変更された異なるオブザーバブルのセットを返すことができると仮定します

GetCurrentValues()は関数だと思います。計算できる場合、checkedValueCountは魔法のように動作し始めます。

GetCurrentValuesを関数ではなく計算式にすることはできますか?