24

私は複雑なビューモデルを持っています。これは、大量の監視可能なプロパティ、計算された監視可能なプロパティ、書き込み可能な計算された監視可能なプロパティと関数を備えた数百行のJavaScriptコードです。したがって、これを管理することはかなりの課題です。

私が対処しなければならなかった厄介な問題は、計算されたオブザーバブルが定義するとすぐに計算されることです。したがって、オブザーバブルを定義する時点でビューモデルでまだ定義されていない変数を使用すると、変数が定義されていないことを示すエラーが発生します。それは...ファイルのすぐ後でです。

不自然な例を次に示します。

function ViewModel1​(args) {
    var self = this;

    self.firstName = ko.observable(args.firstName);
    self.lastName = ko.observable(args.lastName);
    self.fullName = ko.computed(function () {
        return self.firstName() + ' ' + self.lastName();
    });
}

function ViewModel2​(args) {
    var self = this;

    self.fullName = ko.computed(function () {
        // uh oh, where's firstName?
        return self.firstName() + ' ' + self.lastName();
    });
    self.firstName = ko.observable(args.firstName);
    self.lastName = ko.observable(args.lastName);
}

使用ViewModel1しても問題なく動作します。その時点fullNameで定義され、firstName期待lastNameどおりに機能するように定義されます。使用ViewModel2は機能しません。計算された関数にエラーがあり、firstName定義されていません。

これまで私が行ってきたのは、すべての従属変数が定義された後に、計算されたすべてのオブザーバブルが確実に定義されるようにすることでした。これに伴う問題は、そうすることで、関連する変数を互いに近づけて定義したいときに、一見ランダムな場所で物事が定義されることです。

私が思いついた1つの優れた解決策は、「初期化」オブザーバブルセットを定義し、trueすべての計算されたオブザーバブルがまだ初期化されているかどうかをテストし、そうでない場合は値を計算して返すことです。そうすれば、現在未定義の変数にアクセスする試みは行われません。

function ViewModel3(args) {
    var self = this;
    var initializing = ko.observable(true);

    self.fullName = ko.computed(function () {
        if (!initializing()) {
            return self.firstName() + ' ' + self.lastName();
        }
    });
    self.firstName = ko.observable(args.firstName);
    self.lastName = ko.observable(args.lastName);

    initializing(false);
}

しかし、私の場合、これはあまり実用的ではありません。私は計算されたオブザーバブルをたくさん持っているので、それらすべてでこれを行うと非常に肥大化するでしょう、私がこれらをたくさん持っていることを覚えておいてください。それを絞ることは違いを生まないようです。

計算されたオブザーバブルの値を計算する前に待機するようにノックアウトに指示する方法はありますか?または、これに対処するためにコードを構造化するためのより良い方法はありますか?

初期化ロジックを管理するためにいくつかのヘルパー関数を作成することもできますが、それでも、計算された監視可能な定義をすべて変更する必要があります。ノックアウトにこのようなオプションがあることに気付いていないので、この初期化ロジックを追加するためにモンキーパッチノックアウトを使用できると思います。以前に計算されたオブザーバブルのソースを調べましたが、他の場所にすでに設定があるかどうかはわかりません。

jsfiddleデモ

4

1 に答える 1

40

計算されたオブザーバブルは、deferEvaluation何かが実際に計算された値を取得しようとするまで、初期評価が行われないようにするオプションを受け入れます。

次のように定義します。

self.fullName = ko.computed({
   read: function() {
       return self.firstName() + " " + self.lastName();
   },
   deferEvaluation: true
});

完全を期すために、次のように指定することもできます。

this.fullName = ko.computed(function() {
       return this.firstName() + " " + this.lastName();
 }, this, { deferEvaluation: true });

または、次のようにラップすることもできます。

ko.deferredComputed = function(evaluatorOrOptions, target, options) {
   options = options || {};

   if (typeof evaluatorOrOptions == "object") {
       evaluatorOrOptions.deferEvaluation = true;   
   } else {
       options.deferEvaluation = true;
   }

   return ko.computed(evaluatorOrOptions, target, options);
};
于 2012-07-19T21:32:10.430 に答える