web-dev-qa-db-ja.com

動的に生成された要素のノックアウトデータバインド

動的に生成された要素でノックアウトデータバインドを機能させるにはどうすればよいですか?たとえば、単純なhtml選択メニューをdiv内に挿入し、ノックアウトオプションバインディングを使用してオプションを設定します。これは私のコードのようです:

$('#menu').html('<select name="list" data-bind="options: listItems"></select>');

しかし、この方法は機能しません。何か案は?

45
King Julien

ビューモデルをバインドした後にこの要素をオンザフライで追加すると、ビューモデルには含まれなくなり、更新されません。次の2つのいずれかを実行できます。

  1. DOMに要素を追加し、ko.applyBindings();を再度呼び出して再バインドします
  2. または、リストを最初からDOMに追加し、ビューモデルのオプションコレクションを空のままにします。 Knockoutは、後でその場でオプションに要素を追加するまでレンダリングしません。
31
PlTaylor

ノックアウト3.3

ko.bindingHandlers.htmlWithBinding = {
          'init': function() {
            return { 'controlsDescendantBindings': true };
          },
          'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
              element.innerHTML = valueAccessor();
              ko.applyBindingsToDescendants(bindingContext, element);
          }
    };

上記のコードスニペットでは、「htmlWithBinding」プロパティを使用してHTML要素を動的に挿入できます。追加された子要素も評価されます...つまり、データバインド属性です。

12
Stevanicus

htmlバインディングコードを書き換えるか、新しいものを作成します。 htmlバインディングは、動的htmlで「注入されたバインディング」を防ぐため:

ko.bindingHandlers['html'] = {
  //'init': function() {
  //  return { 'controlsDescendantBindings': true }; // this line prevents parse "injected binding"
  //},
  'update': function (element, valueAccessor) {
    // setHtml will unwrap the value if needed
    ko.utils.setHtml(element, valueAccessor());
  }
};
10
Salomón

V3.4.0の場合、以下のカスタムバインディングを使用します。

ko.bindingHandlers['dynamicHtml'] = {
    'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        // setHtml will unwrap the value if needed
        ko.utils.setHtml(element, valueAccessor());
        ko.applyBindingsToDescendants(bindingContext, element);
    }
};
4
vivanov

編集: LosManosが指すバージョン2.3 IIRC以降では機能しないようです

MyViewModel [newObservable] = ko.observable( '')を使用して、ビューモデルに別のオブザーバブルを追加できます。

その後、再びko.applyBindingsを呼び出します。

これは、段落を動的に追加し、新しいビューモデルとバインディングが問題なく機能するシンプルなページです。

// myViewModel starts only with one observable
        var myViewModel = {
            paragraph0: ko.observable('First')
        };
    
        var count = 0;
    
        $(document).ready(function() {
                ko.applyBindings(myViewModel);
    
                $('#add').click(function() {
                        // Add a new paragraph and make the binding
                        addParagraph();
                        // Re-apply!
                        ko.applyBindings(myViewModel);                  
                        return false;   
                });
        });
    
        function addParagraph() {
                count++;
                var newObservableName = 'paragraph' + count;
            $('<p data-bind="text: ' + newObservableName + '"></p>').appendTo('#placeholder');
                
            // Here is where the magic happens
                myViewModel[newObservableName] = ko.observable('');
                myViewModel[newObservableName](Math.random());
    
                // You can also test it in the console typing
                // myViewModel.paragraphXXX('a random text')
        }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>

<div id="placeholder">
    <p data-bind="text: paragraph0"></p>
</div>
    
<a id="add" href="#">Add paragraph</a>
3
Ivan Malagon

それは古い質問ですが、うまくいけば私の最新の答えです(knockout 3.3.0):

ノックアウトテンプレートまたはカスタムコンポーネントを使用して、事前バインドされたオブザーバブルコレクションに要素を追加すると、ノックアウトはすべてを自動的にバインドします。あなたの例は、メニュー項目の観察可能なコレクションが箱から出して仕事をするように見えます。

2
johanneslink

この既存の答え に基づいて、私はあなたの最初の意図に似た何かを達成しました:

_function extendBinding(ko, container, viewModel) {
    ko.applyBindings(viewModel, container.children()[container.children().length - 1]);
}

function yourBindingFunction() {
    var container = $("#menu");
    var inner = $("<select name='list' data-bind='options: listItems'></select>");
    container.empty().append(inner);


    extendBinding(ko, container, {
        listItems: ["item1", "item2", "item3"]
    });
}
_

ここに JSFiddle があります。

新しい要素がdomの一部になったら、_ko.applyBindings_-を呼び出して再バインドすることはできませんので、container.empty()を使用しています。新しい要素を保持し、ビューモデルの変更に合わせて変更する必要がある場合は、viewModelメソッドのextendBindingパラメーターにオブザーバブルを渡します。

0
Ivaylo Slavov
0
Antoni