115

ユーザーが複数回実行できる機能をWebページに構築しています。ユーザーのアクションにより、オブジェクト/モデルが作成され、ko.applyBindings()を使用してHTMLに適用されます。

データバインドされたHTMLは、jQueryテンプレートを介して作成されます。

ここまでは順調ですね。

2番目のオブジェクト/モデルを作成してko.applyBindings()を呼び出すことでこの手順を繰り返すと、次の2つの問題が発生します。

  1. マークアップには、以前のオブジェクト/モデルと新しいオブジェクト/モデルが表示されます。
  2. オブジェクト/モデルのプロパティの1つに関連してjavascriptエラーが発生しますが、それはまだマークアップでレンダリングされています。

この問題を回避するために、最初のパスの後、jQueryの.empty()を呼び出して、すべてのデータバインド属性を含むテンプレート化されたHTMLを削除し、DOMに存在しないようにします。ユーザーが2番目のパスのプロセスを開始すると、データにバインドされたHTMLがDOMに再度追加されます。

しかし、私が言ったように、HTMLがDOMに再追加され、新しいオブジェクト/モデルに再バインドされると、最初のオブジェクト/モデルからのデータが含まれ、発生しないJSエラーが発生します。最初のパスの間。

結論は、マークアップがDOMから削除されたとしても、Knockoutはこれらのバインドされたプロパティを保持しているようです。

したがって、私が探しているのは、これらのバインドされたプロパティをKnockoutから削除する手段です。観察可能なモデルがなくなったことをノックアウトに伝えます。これを行う方法はありますか?

編集

基本的なプロセスは、ユーザーがファイルをアップロードすることです。次に、サーバーはJSONオブジェクトで応答し、データバインドされたHTMLがDOMに追加され、JSONオブジェクトモデルがこのHTMLにバインドされます。

mn.AccountCreationModel = new AccountViewModel(jsonData.Account);
ko.applyBindings(mn.AccountCreationModel);

ユーザーがモデルでいくつかの選択を行うと、同じオブジェクトがサーバーにポストバックされ、データにバインドされたHTMLがDOMから削除され、次のJSが作成されます。

mn.AccountCreationModel = null;

ユーザーがこれをもう一度実行したい場合は、これらすべての手順が繰り返されます。

コードが「関与」しすぎてjsFiddleデモを実行できないのではないかと思います。

4

10 に答える 10

174

DOM 要素でノックアウトの clean node メソッドを呼び出して、メモリ内のバインドされたオブジェクトを破棄しようとしましたか?

var element = $('#elementId')[0]; 
ko.cleanNode(element);

次に、新しいビュー モデルを使用してその要素だけに再度ノックアウト バインディングを適用すると、ビュー バインディングが更新されます。

于 2012-04-06T22:00:20.820 に答える
31

私が取り組んでいるプロジェクトko.unapplyBindingsでは、jQuery ノードと remove ブール値を受け入れる単純な関数を作成しました。ko.cleanNodeメソッドはそれを処理しないため、最初にすべての jQuery イベントのバインドを解除します。メモリリークをテストしましたが、問題なく動作しているようです。

ko.unapplyBindings = function ($node, remove) {
    // unbind events
    $node.find("*").each(function () {
        $(this).unbind();
    });

    // Remove KO subscriptions and references
    if (remove) {
        ko.removeNode($node[0]);
    } else {
        ko.cleanNode($node[0]);
    }
};
于 2012-11-19T18:30:47.087 に答える
12

ノックアウトが提供する with バインディングを使用してみることができます: http://knockoutjs.com/documentation/with-binding.html アイデアは、適用バインディングを 1 回使用し、データが変更されるたびにモデルを更新することです。

最上位のビュー モデル storeViewModel、cartViewModel で表されるカート、およびそのカート内のアイテムのリスト (cartItemsViewModel など) があるとします。

最上位モデルである storeViewModel をページ全体にバインドします。次に、カートまたはカート項目を担当するページの部分を分離できます。

cartItemsViewModel に次の構造があると仮定します。

var actualCartItemsModel = { CartItems: [
  { ItemName: "FirstItem", Price: 12 }, 
  { ItemName: "SecondItem", Price: 10 }
] }

最初は、cartItemsViewModel を空にすることができます。

手順は次のようになります。

  1. html でバインディングを定義します。cartItemsViewModel バインディングを分離します。

      
        <div data-bind="with: cartItemsViewModel">
          <div data-bind="foreach: CartItems">
            <span data-bind="text: ItemName"></span>
            <span data-bind="text: Price"></span>
          </div>
        </div>
      
    
  2. ストア モデルはサーバーから取得されます (または他の方法で作成されます)。

    var storeViewModel = ko.mapping.fromJS(modelFromServer)

  3. 最上位ビュー モデルで空のモデルを定義します。次に、そのモデルの構造を実際のデータで更新できます。

      
        storeViewModel.cartItemsViewModel = ko.observable();
        storeViewModel.cartViewModel = ko.observable();
     
    
  4. 最上位のビュー モデルをバインドします。

    ko.applyBindings(storeViewModel);

  5. cartItemsViewModel オブジェクトが使用可能になったら、それを以前に定義したプレースホルダーに割り当てます。

    storeViewModel.cartItemsViewModel(actualCartItemsModel);

カートの商品をクリアしたい場合: storeViewModel.cartItemsViewModel(null);

Knockout は html を処理します。つまり、モデルが空でない場合に表示され、div の内容 (「バインディングあり」のもの) が消えます。

于 2013-07-23T07:45:59.930 に答える
9

検索ボタンがクリックされるたびに ko.applyBinding を呼び出す必要があり、フィルタリングされたデータがサーバーから返されます。この場合、ko.cleanNode を使用せずに次の作業を行います。

foreach をテンプレートに置き換えると、collections/observableArray の場合は問題なく動作するはずです。

このシナリオは役に立つかもしれません。

<ul data-bind="template: { name: 'template', foreach: Events }"></ul>

<script id="template" type="text/html">
    <li><span data-bind="text: Name"></span></li>
</script>
于 2013-01-16T06:14:51.513 に答える
6

KO の内部関数を使用して JQuery のブランケット イベント ハンドラーの削除に対処する代わりに、withortemplateバインディングを使用する方がはるかに優れています。これを行うと、ko は DOM のその部分を再作成するため、自動的にクリーンアップされます。これも推奨される方法です。https ://stackoverflow.com/a/15069509/207661 を参照してください。

于 2014-01-03T07:47:44.353 に答える
4

バインディングをずっと保持し、それに関連付けられているデータを更新するだけの方がよいと思います。.resetAll()私はこの問題に遭遇し、データを保持していた配列でメソッドを使用して呼び出すことが、これを行う最も効果的な方法であることがわかりました。

基本的に、ViewModel を介してレンダリングされるデータを含むグローバル var から始めることができます。

var myLiveData = ko.observableArray();

myLiveData通常の配列を作成するだけではできないことに気付くまでにしばらく時間がかかりました。そのko.oberservableArray部分が重要でした。

その後、先に進んで、やりたいことを何でもできますmyLiveData。たとえば、次のように$.getJSON電話をかけます。

$.getJSON("http://foo.bar/data.json?callback=?", function(data) {
    myLiveData.removeAll();
    /* parse the JSON data however you want, get it into myLiveData, as below */
    myLiveData.push(data[0].foo);
    myLiveData.push(data[4].bar);
});

これが完了したら、先に進み、通常どおり ViewModel を使用してバインディングを適用できます。

function MyViewModel() {
    var self = this;
    self.myData = myLiveData;
};
ko.applyBindings(new MyViewModel());

次に、HTML でmyData通常どおりに使用します。

このようにして、どの関数からでも myLiveData をいじることができます。たとえば、数秒ごとに更新したい場合は、その$.getJSON行を関数でラップして呼び出すsetIntervalだけです。myLiveData.removeAll();ラインを入れておくことを忘れない限り、バインディングを外す必要はありません。

データが非常に巨大でない限り、ユーザーはアレイをリセットしてから最新のデータを追加し直すまでの時間に気付くことさえできません。

于 2013-10-22T05:23:55.773 に答える
2

私は最近メモリリークの問題を抱えていましたがko.cleanNode(element);、私のためにそれをしませんko.removeNode(element);でした. Javascript + Knockout.js メモリ リーク - オブジェクトが破棄されていることを確認する方法は?

于 2014-05-01T15:44:07.970 に答える
0

ビュー モデルに多くの div バインディングが含まれている場合、これをクリアする最善の方法ko.applyBindings(new someModelView);は使用することであることがわかりました。ko.cleanNode($("body")[0]);ko.applyBindings(new someModelView2);

于 2013-07-03T15:43:14.947 に答える