1

次の js があるとします。

  var vm = {
    objects: ko.observable([]),
    objectCount: ko.computed(function(){
      return vm && vm.objects().length;
    }),

    add: function() {
      var current = vm.objects();
      current.push({});      
      console.log('current is', current);
      vm.objects(current);
      console.log("should recalculate here", vm.objectCount());
    }
  };

そして、次のhtml:

  <ul data-bind="foreach: objects">
    <li>
      Object: <span data-bind="text: $index"></span>
    </li>
  </ul>
  <button data-bind="click: add">Add Object</button>
  <p>
    Total number of objects:
    <span data-bind="text: objectCount"></span>
  </p>

オブジェクトを追加した後に objectCount() を呼び出すため、ドキュメントを読んで、その依存関係を再計算する必要があることを理解しています。代わりに、一度だけ実行して、関数を実行することさえないようです!

私の問題の簡略化されたバージョンを示す JSBin。

4

3 に答える 3

4

viewModel を定義した後に計算を定義する - http://jsbin.com/welcome/58760/ - 計算されたオブザーバブルが機能する方法が原因で発生します (ko docs から)。

  1. 計算されたオブザーバブルを宣言すると、KO はすぐにその評価関数を呼び出して初期値を取得します。
  2. エバリュエーター関数が実行されている間、KO は、エバリュエーターが値を読み取るオブザーバブル (または計算されたオブザーバブル) のログを保持します。
  3. エバリュエーターが終了すると、KO は、触れた各オブザーバブル (または計算されたオブザーバブル) へのサブスクリプションをセットアップします。サブスクリプション コールバックは、
    エバリュエーターが再度実行されるように設定され、
    プロセス全体をステップ 1 にループバックします (
    適用されなくなった古いサブスクリプションを破棄します)。
  4. KO は、計算されたオブザーバブルの新しい値についてサブスクライバーに通知します。

vm オブジェクト内でオブザーバブルをインスタンス化するとき、他のプロパティはまだ存在しません。

于 2012-12-07T17:07:57.387 に答える
2

それは単なるスコープの問題です。スクリプト コードを次のようにリファクタリングすると、次のようになります。

$(function(){
  var vm = function(){
    var self = this;

    self.objects = ko.observable([]);
    self.objectCount = ko.computed(function(){
      return self.objects().length;
    });

    self.add = function() {
      var current = self.objects();
      current.push({});      
      console.log('current is', current);
      self.objects(current);
      console.log("should recalculate here", self.objectCount());
    };
  };

  ko.applyBindings(new vm());
});

次に、正しい変数がスコープされ、Knockout が依存関係を正しく計算します。guigouzが述べたように、ko.computedが最初に呼び出されるときvmは未定義であるため、変更ハンドラをセットアップできません。

これが更新されたJSBinです

于 2012-12-07T17:03:37.357 に答える
2

Another approach is to use the deferEvaluation option for ko.computed. This will tell Knockout to wait to evaluate the computed observable until it's first used. By that time, vm will be defined.

objectCount: ko.computed(function(){
  return vm && vm.objects().length;
}, null, { deferEvaluation: true }),
于 2012-12-07T20:55:41.713 に答える