web-dev-qa-db-ja.com

knockout.js:バインディングを更新しますか?

ko.applyBindings()の後にDOMに新しい要素を挿入するとき。呼び出された場合、ノックアウトはこれらの新しい要素を認識しません。私はこれがなぜ起こっているのか理解できます-それらはノックアウトによってインデックスされていないだけです。

だから、最初はko.applyBindings()をもう一度呼び出すだけでこれが解決されると思ったのですが、新しい要素を追加した後、私はko.applyBindings()を呼び出すたびに、対応するイベントが複数回発生することに気付きました。したがって、5回適用した後、click:バインディングが5回実行されるため、これは望ましい解決策ではありません;)

Ko.updateBindings()など、ノックアウトを指示するものはありますか?要素のバインディングを更新しますか?

あいさつ、クリス

36
Christian Engel

ko.applyBindingsを呼び出すたびに、DOM全体のバインディングが検査されます。結果として、これを複数回実行すると、各要素に対して複数のバインディングが取得されます。新しいDOM要素をバインドするだけの場合、この要素をパラメーターとしてapplyBindings関数に渡すことができます。

ko.applyBindings(viewModelA, document.getElementById("newElement"));

この関連質問を参照してください。

ko.applyBindingsを呼び出して部分ビューをバインドできますか?

36
ColinE

自分が何をしているのかを正確に知ることなく、これについて間違った方向に進んでいるように見えます。ビューは、ビューモデルによって駆動される必要があります。そのため、ノックアウトバインディングを適用する必要があるDOM要素を直接追加しないでください。

代わりに、ビューの変更を反映するようにビューモデルを更新する必要があります。これにより、新しい要素が表示されます。

たとえば、$('body').append('<a href="#" data-bind="click: something">Click me!</a>');の場合、ボタンを表示する必要があるときにDOM要素を追加するのではなく、ビューモデルを使用してボタンの表示を制御します。

あなたのビューモデルには

_var viewModel = { clickMeAvailable: ko.observable(false) }
_

そしてあなたのHTMLには

_<a href="#" data-bind="click: something, visible: clickMeAvailable">Click me!</a>
_

アプリケーションの状態が変更されて「クリックして」ボタンが使用可能になったら、viewModel.clickMeAvailable(true)だけを実行します。

これを行うポイント、およびノックアウトの大部分は、ビジネスロジックをプレゼンテーションから分離することです。したがって、click meを使用可能にするコードは、click meがボタンを含むことを気にしません。 Click Meが利用可能になったら、_viewModel.clickMeAvailable_を更新するだけです。

たとえば、フォームが有効に入力されたときに使用できるようにする必要があるクリックボタンは「保存」ボタンであるとします。保存ボタンの可視性を、観察可能なformValidビューモデルに結び付けます。

ただし、フォームを有効にした後、保存する前に同意する必要がある法的合意が表示されるように、物事を変更することにします。フォームのロジックは変更されません。フォームが有効な場合でも、formValidが設定されます。 formValidが変更されたときに起こることを変更するだけです。

Lassombraがこの回答のコメントで指摘しているように、直接DOM操作が最良のアプローチである場合があります。たとえば、必要なときにビューの一部のみをハイドレートする複雑な動的ページなどです。しかし、これを行うことで、Knockoutが提供する懸念事項の分離をあきらめています。このトレードオフを検討する場合は注意してください。

7
SamStephens

あなたがずっと前に尋ねたのは知っていますが、私は同じような問題に出くわしました。コンテナに新しい要素を追加し、それらにonclick機能を与えようとしました。最初にあなたがやったことを試し、さらにアプローチを試しました ColinE推奨 。これは私にとって実用的な解決策ではなかったので、私は SamStephens アプローチを試し、それを思いつきました。

HTML:

<div id="workspace" data-bind="foreach:nodeArr, click:addNode">
<div class="node" data-bind="attr:{id:nodeID},style:{left:nodeX,top:nodeY},text:nodeID, click:$parent.changeColor"></div>
</div>

JavaScript:

<script>
function ViewModel() {
var self = this;
var id = 0;
self.nodeArr = ko.observableArray();
self.addNode = function (data, event) {
    self.nodeArr.Push({
        'nodeID': 'node' + id,
        'nodeX' : (event.offsetX - 25) + 'px',
        'nodeY' : (event.offsetY - 10) + 'px'
    })
    id++;
}
self.changeColor = function(data, event){
    event.stopPropagation();
    event.target.style.color = 'green';
    event.target.style.backgroundColor = 'white';
}
}
ko.applyBindings(new ViewModel());
</script>

JS Fiddle で作成できます。これがまだ誰かを助けることを願っています。

0