javascript $data - knockout data-bind on dynamically generated elements





div to (8)


Checkout this answer: How do define a custom knockout 'options binding' with predefined Text and Value options

ko.applyBindingsToNode is particularly useful.

How is it possible to make knockout data-bind work on dynamically generated elements? For example, I insert a simple html select menu inside a div and want to populate options using the knockout options binding. 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. You can do one of two things.

  1. Add the element to the DOM and re-bind it by calling ko.applyBindings(); again
  2. 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.



rewrite html binding code or create a new. Because html binding prevents "injected bindings" in dynamical 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:

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



Knockout 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. The child elements which are added are then also evaluated... i.e. their data-bind attributes.




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

You can add another observable to your view model using myViewModel[newObservable] = ko.observable('')

After that, call again to 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):

When using knockout templates or custom components to add elements to prebound observable collections, knockout will bind everything automatically. Your example looks like an observable collection of menu items would do the job out of the box.




As of jQuery 1.4 you can pass attributes to a self-closed element like so:

jQuery('<div/>', {
    id: 'some-id',
    class: 'some-class',
    title: 'now this div has a title!'
}).appendTo('#mySelector');

Here it is in the Docs

Examples can be found at jQuery 1.4 Released: The 15 New Features you Must Know .





javascript jquery knockout.js