Skip to content

Commit

Permalink
added $index value in the binding context of foreach templates.
Browse files Browse the repository at this point in the history
  • Loading branch information
barkmadley committed Oct 22, 2011
1 parent 7e3ebc3 commit ad5beb8
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 11 deletions.
11 changes: 10 additions & 1 deletion spec/templatingBehaviors.js
Expand Up @@ -350,6 +350,15 @@ describe('Templating', {
ko.applyBindings({ myCollection: myArray }, testNode);
value_of(testNode.childNodes[0]).should_contain_html("<div>the item is <span>bob</span></div><div>the item is <span>frank</span></div>");
},

'Data binding \'foreach\' option should apply bindings with an $index in the context': function () {
var myArray = new ko.observableArray([{ personName: "Bob" }, { personName: "Frank"}]);
ko.setTemplateEngine(new dummyTemplateEngine({ itemTemplate: "The item # is <span data-bind='text: $index'></span>" }));
testNode.innerHTML = "<div data-bind='template: { name: \"itemTemplate\", foreach: myCollection }'></div>";

ko.applyBindings({ myCollection: myArray }, testNode);
value_of(testNode.childNodes[0]).should_contain_html("<div>the item # is <span>0</span></div><div>the item # is <span>1</span></div>");
},

'Data binding \'foreach\' option should update DOM nodes when a dependency of their mapping function changes': function() {
var myObservable = new ko.observable("Steve");
Expand Down Expand Up @@ -650,4 +659,4 @@ describe('Templating', {
ko.applyBindings({ someData: { childProp: 'abc' } }, testNode);
value_of(testNode).should_contain_html("start <!-- ko template: { data: somedata } --><div>childprop: abc</div><!-- /ko -->end");
}
})
})
10 changes: 5 additions & 5 deletions src/binding/editDetection/arrayToDomNodeChildren.js
Expand Up @@ -10,11 +10,11 @@
// "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
// You can use this, for example, to activate bindings on those nodes.

function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes) {
function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
// Map this array value inside a dependentObservable so we re-map when any dependency changes
var mappedNodes = [];
var dependentObservable = ko.dependentObservable(function() {
var newMappedNodes = mapping(valueToMap) || [];
var newMappedNodes = mapping(valueToMap, index) || [];

// On subsequent evaluations, just replace the previously-inserted DOM nodes
if (mappedNodes.length > 0) {
Expand Down Expand Up @@ -77,9 +77,9 @@

case "added":
var valueToMap = editScript[i].value;
var mapData = mapNodeAndRefreshWhenChanged(domNode, mapping, valueToMap, callbackAfterAddingNodes);
var mapData = mapNodeAndRefreshWhenChanged(domNode, mapping, valueToMap, callbackAfterAddingNodes, i);
var mappedNodes = mapData.mappedNodes;

// On the first evaluation, insert the nodes at the current insertion point
newMappingResult.push({ arrayEntry: editScript[i].value, domNodes: mappedNodes, dependentObservable: mapData.dependentObservable });
for (var nodeIndex = 0, nodeIndexMax = mappedNodes.length; nodeIndex < nodeIndexMax; nodeIndex++) {
Expand All @@ -99,7 +99,7 @@
insertAfterNode = node;
}
if (callbackAfterAddingNodes)
callbackAfterAddingNodes(valueToMap, mappedNodes);
callbackAfterAddingNodes(valueToMap, mappedNodes, i);
break;
}
}
Expand Down
12 changes: 7 additions & 5 deletions src/templating/templating.js
Expand Up @@ -117,8 +117,10 @@
};

ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
var createInnerBindingContext = function(arrayValue) {
return parentBindingContext.createChildContext(ko.utils.unwrapObservable(arrayValue));
var createInnerBindingContext = function(arrayValue, index) {
var result = parentBindingContext.createChildContext(ko.utils.unwrapObservable(arrayValue));
result['$index'] = index;
return result;
};

// This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
Expand All @@ -139,10 +141,10 @@
return options['includeDestroyed'] || !ko.utils.unwrapObservable(item['_destroy']);
});

ko.utils.setDomNodeChildrenFromArrayMapping(targetNode, filteredArray, function (arrayValue) {
ko.utils.setDomNodeChildrenFromArrayMapping(targetNode, filteredArray, function (arrayValue, index) {
// Support selecting template as a function of the data being rendered
var templateName = typeof(template) == 'function' ? template(arrayValue) : template;
return executeTemplate(null, "ignoreTargetNode", templateName, createInnerBindingContext(arrayValue), options);
return executeTemplate(null, "ignoreTargetNode", templateName, createInnerBindingContext(arrayValue, index), options);
}, options, activateBindingsCallback);

}, null, { 'disposeWhenNodeIsRemoved': targetNode });
Expand Down Expand Up @@ -223,4 +225,4 @@
})();

ko.exportSymbol('ko.setTemplateEngine', ko.setTemplateEngine);
ko.exportSymbol('ko.renderTemplate', ko.renderTemplate);
ko.exportSymbol('ko.renderTemplate', ko.renderTemplate);

0 comments on commit ad5beb8

Please sign in to comment.