Подтвердить что ты не робот

Привязка данных нокаута к динамически генерируемым элементам

Как можно сделать работу по привязке данных к нокауту динамически сгенерированным элементам? Например, я вставляю простое меню выбора html внутри div и хочу заполнять опции с помощью привязки опций нокаута. Вот как выглядит мой код:

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

но этот метод не работает. Любые идеи?

4b9b3361

Ответ 1

Если вы добавите этот элемент "на лету" после того, как вы связали свою модель просмотра, он не будет отображаться в режиме просмотра и не будет обновляться. Вы можете сделать одну из двух вещей.

  • Добавьте элемент в DOM и снова привяжите его, вызвав ko.applyBindings(); снова
  • ИЛИ добавьте список в DOM с самого начала и оставьте коллекцию опций в вашей модели view пустым. Нокаут не будет отображаться, пока вы не добавите элементы в опции на лету позже.

Ответ 2

Нокаут 3.3

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

Над фрагментом кода вы можете динамически вводить элементы html с помощью свойства htmlWithBinding. Затем добавляются дочерние элементы, которые добавляются, то есть их атрибуты привязки данных.

Ответ 3

переписать 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());
  }
};

Ответ 4

Для 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);
    }
};

Ответ 5

EDIT: Кажется, что это не работает с версии 2.3 IIRC, как указано LosManos

Вы можете добавить еще одну наблюдаемую модель вашего вида, используя 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>

Ответ 6

Это старый вопрос, но здесь я надеюсь, что последний ответ (нокаут 3.3.0):

При использовании шаблонов нокаута или пользовательских компонентов для добавления элементов в предвоенные наблюдаемые коллекции нокаут автоматически свяжет все. Ваш пример похож на наблюдаемую коллекцию пунктов меню, которая выполнит задание из коробки.

Ответ 7

Основываясь на этом существующем ответе, я достиг чего-то похожего на ваши первоначальные намерения:

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.