diff --git a/spec/templatingBehaviors.js b/spec/templatingBehaviors.js
index 77281e8e6..588a579e6 100644
--- a/spec/templatingBehaviors.js
+++ b/spec/templatingBehaviors.js
@@ -350,6 +350,15 @@ describe('Templating', {
ko.applyBindings({ myCollection: myArray }, testNode);
value_of(testNode.childNodes[0]).should_contain_html("
the item is bob
the item is frank
");
},
+
+ '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 " }));
+ testNode.innerHTML = "";
+
+ ko.applyBindings({ myCollection: myArray }, testNode);
+ value_of(testNode.childNodes[0]).should_contain_html("the item # is 0
the item # is 1
");
+ },
'Data binding \'foreach\' option should update DOM nodes when a dependency of their mapping function changes': function() {
var myObservable = new ko.observable("Steve");
@@ -650,4 +659,4 @@ describe('Templating', {
ko.applyBindings({ someData: { childProp: 'abc' } }, testNode);
value_of(testNode).should_contain_html("start childprop: abc
end");
}
-})
\ No newline at end of file
+})
diff --git a/src/binding/editDetection/arrayToDomNodeChildren.js b/src/binding/editDetection/arrayToDomNodeChildren.js
index 6b1294aa3..ef2e48a3d 100644
--- a/src/binding/editDetection/arrayToDomNodeChildren.js
+++ b/src/binding/editDetection/arrayToDomNodeChildren.js
@@ -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) {
@@ -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++) {
@@ -99,7 +99,7 @@
insertAfterNode = node;
}
if (callbackAfterAddingNodes)
- callbackAfterAddingNodes(valueToMap, mappedNodes);
+ callbackAfterAddingNodes(valueToMap, mappedNodes, i);
break;
}
}
diff --git a/src/templating/templating.js b/src/templating/templating.js
index 2d09395be..67ed903e1 100644
--- a/src/templating/templating.js
+++ b/src/templating/templating.js
@@ -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
@@ -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 });
@@ -223,4 +225,4 @@
})();
ko.exportSymbol('ko.setTemplateEngine', ko.setTemplateEngine);
-ko.exportSymbol('ko.renderTemplate', ko.renderTemplate);
\ No newline at end of file
+ko.exportSymbol('ko.renderTemplate', ko.renderTemplate);