简体   繁体   English

敲除数据绑定动态生成的元素

[英]knockout data-bind on dynamically generated elements

How is it possible to make knockout data-bind work on dynamically generated elements? 怎样才能使knockout数据绑定对动态生成的元素起作用? For example, I insert a simple html select menu inside a div and want to populate options using the knockout options binding. 例如,我在div中插入一个简单的html选择菜单,并希望使用knockout选项绑定填充选项。 This is what my code looks like: 这就是我的代码:

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

but this method doesn't work. 但这种方法不起作用。 Any ideas? 有任何想法吗?

If you add this element on the fly after you have bound your viewmodel it will not be in the viewmodel and won't update. 如果在绑定viewmodel后动态添加此元素,则它将不在viewmodel中,并且不会更新。 You can do one of two things. 你可以做两件事之一。

  1. Add the element to the DOM and re-bind it by calling ko.applyBindings(); 将元素添加到DOM并通过调用ko.applyBindings();重新绑定它ko.applyBindings(); again 再次
  2. OR add the list to the DOM from the beginning and leave the options collection in your viewmodel empty. 或者从头开始将列表添加到DOM,并将viewmodel中的选项集合留空。 Knockout won't render it until you add elements to options on the fly later. Knockout将不会呈现它,直到您稍后向选项添加元素。

Knockout 3.3 淘汰赛3.3

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

Above code snippet allows you to inject html elements dynamically with the "htmlWithBinding" property. 上面的代码片段允许您使用“htmlWithBinding”属性动态注入html元素。 The child elements which are added are then also evaluated... ie their data-bind attributes. 然后还评估添加的子元素......即它们的数据绑定属性。

rewrite html binding code or create a new. 重写html绑定代码或创建一个新的。 Because html binding prevents "injected bindings" in dynamical 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()); } }; 

For v3.4.0 use the custom binding below: 对于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);
    }
};

EDIT: It seems that this doesn't work since version 2.3 IIRC as pointed by LosManos 编辑:似乎这不是因为版本2.3 IIRC,如LosManos所指出的那样

You can add another observable to your view model using myViewModel[newObservable] = ko.observable('') 您可以使用myViewModel [newObservable] = ko.observable('')向视图模型中添加另一个observable

After that, call again to ko.applyBindings. 之后,再次调用ko.applyBindings。

Here is a simple page where I add paragraphs dynamically and the new view model and the bindings work flawlessly. 这是一个简单的页面,我动态添加段落,新的视图模型和绑定工作完美无缺。

 // 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> 

It's an old question but here's my hopefully up-to-date answer (knockout 3.3.0): 这是一个老问题,但这是我希望最新的答案(淘汰赛3.3.0):

When using knockout templates or custom components to add elements to prebound observable collections, knockout will bind everything automatically. 当使用挖空模板或自定义组件向预绑定的可观察集合添加元素时,knockout将自动绑定所有内容。 Your example looks like an observable collection of menu items would do the job out of the box. 您的示例看起来像一个可观察的菜单项集合将开箱即用。

Based on this existing answer , I've achived something similar to your initial intentions: 基于现有的答案 ,我已经实现了与您最初的意图类似的东西:

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"]
    });
}

Here is a JSFiddle to play with. 这是一个可以玩的JSFiddle

Be warned, once the new element is part of the dom, you cannot re-bind it with a call to ko.applyBindings - that is why I use container.empty() . 请注意,一旦新元素成为dom的一部分,就不能通过调用ko.applyBindings来重新绑定它 - 这就是我使用container.empty() If you need to preserve the new element and make it change as the view model changes, pass an observable to the viewModel parameter of the extendBinding method. 如果需要保留新元素并在视图模型更改时进行更改, viewModel observable传递给extendBinding方法的viewModel参数。

Checkout this answer: How do define a custom knockout 'options binding' with predefined Text and Value options 查看此答案: 如何使用预定义的文本和值选项定义自定义挖空'选项绑定'

ko.applyBindingsToNode is particularly useful. ko.applyBindingsToNode特别有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM