existing content mapped to observableArray
https://groups.google.com/d/topic/knockoutjs/OJamQFg3Y9c/discussion
by rniemeyer
HTML
<script src="http://knockoutjs.com/downloads/knockout-1.3.0beta.debug.js"></script>
<ul id="test" data-bind="templateFromExisting: { foreach: items }">
<li>
<input value="one" data-bind="value: name" />
<a href="#" class="remove">delete</a>
</li>
<li>
<input value="two" data-bind="value: name" />
<a href="#" class="remove">delete</a>
</li>
<li>
<input value="three" data-bind="value: name" />
<a href="#" class="remove">delete</a>
</li>
</ul>
<button data-bind="click: addItem">Add Item</button>
<hr/>
<div data-bind="text: ko.toJSON(viewModel)"></div>
CSS
a { font-size: .75em; }
.selected { background-color: #CCC; }
JavaScript
ko.bindingHandlers.templateFromExisting = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
//Use first element as our template
var bindingValue = ko.utils.unwrapObservable(valueAccessor());
if ((typeof bindingValue != "string") && (!bindingValue.name) && (element.nodeType == 1)) {
// It's an anonymous template - store the element contents
var firstElement = $(element).children()[0],
firstElementHTML = firstElement.outerHTML || $(firstElement).clone().wrap("<div></div>").parent().html();
new ko.templateSources.anonymousTemplate(element).text(firstElementHTML);
}
//TODO: consider "data" or viewModel when not using foreach
var items = ko.utils.unwrapObservable(bindingValue.foreach);
//generate a mapping from the existing elements
var mappingResult = [];
for (var i = 0, j = items.length; i < j; i++) {
var mapping = {},
child = $(element).children()[i];
mapping.arrayEntry = items[i];
mapping.domNodes = [child];
mapping.dependentObservable = ko.dependentObservable(function() { } );
//bind this node and its children
ko.applyBindings(items[i], child);
mappingResult.push(mapping);
}
console.log("lastMapping", mappingResult);
ko.utils.domData.set(element, "setDomNodeChildrenFromArrayMapping_lastMappingResult", mappingResult);
return { 'controlsDescendantBindings': true };
},
update: ko.bindingHandlers.template.update
};
function Item(id, name) {
this.id = ko.observable(id);
this.name = ko.observable(name);
}
var viewModel = {
items: ko.observableArray([
new Item(1, "one"),
new Item(2, "two"),
new Item(3, "three")
]),
addItem: function() {
...