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


80

計算されたプロパティが与えられた

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回の呼び出しを強制するにはどうすればよいですか。


私の更新された「書き直された」答えを参照してください。
Josh

回答:


116

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

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

ただし、ダミーの監視可能な値を作成し、それが変更されたことをサブスクライバーに通知することで、ハッカーでこれを回避できます。

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

}());​

これがこのアプローチを示すフィドルです


ああ、私はこれを試しましたが、間違って接続したに違いありません。これはハッキーに見えますが、良いです(そして、ko.computedを拡張して機能させることができます
George Mauer

いつものように、シンプルなものが最適です。
ヘンリーロドリゲス

1
これは、観察できない大量のデータを変更し、変更後にデータの一部を表示する必要がある場合に役立ちます。
マレクバー

1
notifySubscribers()の使用は良いものです。乱数を作成してそれをdummy()の値に設定するという私が行っていたよりも優れています
2015年

9

あなたに応じて、すべてのオブザーバブルの再計算を強制する方法があります:

getCurrentValues.valueHasMutated()

9
Computedsにはこのメソッドがありません
George Mauer 2014年

getCurrentValues(); //an array of ko.observable[]
ルスタム2014年

ああなるほど。計算されたものの依存関係であるオブザーバブルを見つけて、そのvalueHasMutatedメソッドを呼び出すと言っています。これは、上記のJoshの答えと基本的に何の違いもありませんね。実際、何が参照されているかを知り、それらの参照が観察可能(および計算されていない)であることを知る必要があります。
ジョージマウアー2014年

2
それでも、この関数は読者の選択肢であるため、言及することをお勧めします。ただし、この関数をnotifySubscribers()と交換できる場合や、いずれかの方法でペナルティまたは利点がある場合は、受け入れられた回答を更新して注意することができます。
ショーンウィルソン

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

@mbestコメントからhttps://github.com/knockout/knockout/issues/1019


価値がないとはどういう意味ですか?これに切り替える前に機能しましたか。遅延更新(グローバル設定)を使用していますか。オブザーバブルを更新してすぐに値を使用できると期待する場合は、競合が発生する可能性があることに気づきました。もしそうなら、私のメソッドにko.tasks.runEarly()を追加してみてください。
Simon_Weaver 2017年

1

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

getCurrentValues()は関数だと思います。あなたがそれを計算することができれば、あなたのcheckedValueCountは魔法のように働き始めるでしょう。

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


私は実際のシナリオをかなり単純化しすぎていますが、確かにそうなる可能性があるとしましょう(たとえば、パラメーターを取得する必要がある場合はそうではありません)-それがどのように違いを生むかはわかりません。getCurrentValues()の内部では、他のデータをスライスおよびダイシングして、ツリービューのどのノードを返す必要があるかを判断しています。問題は、関数が異なる観測可能な値を返す可能性があり、それを取得するために計算が必要なことです。基本的に、ドキュメントが動的依存関係について話していることとまったく同じですが、それらの複雑さはその場で追加されます
George Mauer 2012

「スライスとダイシング」がオブザーバブルに基づいていれば、違いが生じます。たとえば、スライスとダイシングが.IsChecked()== trueのノードであるとします。次に、すべてのノードを評価し、.IsChecked()でノードを返す.currentValues()という計算が行われます。観察可能な特性に対してスライスとダイシングを行うことはできますか?
Judah Gabriel Himango 2012

ユダが何を言っているのかよくわかりません。私の場合、すべての呼び出しを観察できるようにすることはできません。しかし、もっと重要なことは、それがどのように問題になるかわからないことです。ノックアウトは何の反省もしません。あなたが呼んだクロージャ(私はチェックしていませんが、javascriptが完全にlisp-landに入っていない限り、これは不可能です)。計算で実行できるのは、呼び出されたオブザーバブルを追跡することだけです。
ジョージマウアー2012

-1

計算されたものを強制的に更新する簡単な方法がないため、toForceComputedUpdateという名前のオブザーバブルを作成し、計算された関数内でそれを呼び出して、計算されたものが更新をリッスンするようにします。次に、更新を強制するために、このようにtoForceComputedUpdate(Math 。ランダム)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.