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

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

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

но этот способ не работает. Есть идеи?

 Vaibhav06 окт. 2014 г., 11:56
Отбросьте идею (авто) привязки KO к этому динамически добавленному элементу DOM и обработайте это вручную.
 PlTaylor16 июн. 2012 г., 23:34
Вы добавляете это после того, как вы сделали ko.applyBindings (yourVMHere);
 Andrew22 февр. 2019 г., 18:29
правильный ответ внизу:stackoverflow.com/a/29903552/3093731

Ответы на вопрос(8)

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

 24 апр. 2015 г., 20:45
Посмотрев на все ответы и комментарии в этой ветке, IMO, на самом деле, это лучшее решение вопроса "нокаут-привязка данных по динамически генерируемым элементам". Хорошее решение!
 22 февр. 2019 г., 18:14
Если бы кто-то, кто понимает это, мог отредактировать это, чтобы быть более понятным, я был бы признателен :)
Решение Вопроса

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

Add the element to the DOM and re-bind it by calling ko.applyBindings(); again OR add the list to the DOM from the beginning and leave the options collection in your viewmodel empty. Knockout won't render it until you add elements to options on the fly later.
 09 апр. 2014 г., 17:18
Да, я понял, что это плохая практика - применять привязки более одного раза к элементу. Поскольку он будет срабатывать 2 раза, я думаю, поэтому они добавили несколько предупреждений в КО 3
 09 апр. 2014 г., 13:42
Это должно быть новой особенностью более поздних структур. Второй вариант все еще жизнеспособен, и, честно говоря, лучший вариант для начала.
 09 апр. 2014 г., 10:11
Если я снова вызываю applyBindings, это выдает ошибку: Ошибка: Вы не можете применять привязки несколько раз к одному и тому же элементу.

Нокаут 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 с помощью & quot; htmlWithBinding & quot; имущество. Затем добавляемые дочерние элементы также оцениваются ... т.е. их атрибуты привязки данных.

EDIT: It seems that this doesn't work since version 2.3 IIRC as pointed by LosManos

Вы можете добавить другую наблюдаемую модель для вашей модели представления, используя myViewModel [newObservable] = ko.observable (& apos; & apos;)

После этого снова позвоните в 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>
&l,t;/div>
    
<a id="add" href="#">Add paragraph</a>

 17 мая 2013 г., 05:02
@ gunteman .. почему бы и нет?
 02 мая 2013 г., 23:37
Вызов applyBindings более одного раза не является хорошей идеей.
 06 окт. 2014 г., 11:54
Это решение не решает проблему. Как правило, динамически добавляемый элемент будет того же типа, что означает, что он должен вызывать тот же обработчик, который должен быть привязан к ВМ. Пример: VM.loadData = f () {processing ..} и хотел бы, чтобы это были данные, привязанные к любому (конкретному) div, который будет динамически добавляться в DOM. Как новый элемент может привязать ту же функцию к его щелчку, используя ваш подход?
 05 июн. 2014 г., 18:39
Похоже, это приводит к тому, что «нельзя применить привязки дважды» ошибка. Можно ли сказать ko.applyBindings () очень специфический элемент, который вы хотите добавить в привязки?
 06 окт. 2014 г., 12:21
Проверьте эту скрипку: jsfiddle.net/rniemeyer/F7pLN

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

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 метод.

Для 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);
    }
};
 12 мар. 2019 г., 10:11
Как тогда назвать эту привязку, когда я создаю новый тег с привязками внутри?

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

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

 22 февр. 2019 г., 18:29
Правильный ответ. Просто загрузите элементы в наблюдаемый массив, а не добавляйте их на страницу напрямую. Вот для чего нужен нокаут. ИЛИ, не привязывайте динамический элемент, пока он не будет добавлен на страницу.

Ваш ответ на вопрос