Permalink
Browse files

Merge pull request #739 from SteveSanderson/739-foreach-with-template…

…-rewriting-bugfix

jquery.tmpl interpolation of observables are not updated when inside data-bind'ed elements
  • Loading branch information...
2 parents b1076c4 + 6205bf5 commit b22cd768725faa1a7bcd00f78b453f7a0bf53a57 @mbest mbest committed Dec 4, 2012
Showing with 23 additions and 1 deletion.
  1. +18 −0 spec/templatingBehaviors.js
  2. +1 −1 src/binding/editDetection/arrayToDomNodeChildren.js
  3. +4 −0 src/utils.js
@@ -445,6 +445,24 @@ describe('Templating', function() {
expect(testNode.childNodes[0]).toContainHtml("<div>new</div>inner <span>123</span>x");
});
+ it('Data binding \'foreach\' should handle templates in which the very first node has a binding but it does not reference any observables', function() {
+ // Represents https://github.com/SteveSanderson/knockout/issues/739
+ // Previously, the rewriting (which introduces a comment node before the bound node) was interfering
+ // with the array-to-DOM-node mapping state tracking
+ ko.setTemplateEngine(new dummyTemplateEngine({ mytemplate: "<div data-bind='attr: {}'>[js:name()]</div>" }));
+ testNode.innerHTML = "<div data-bind=\"template: { name: 'mytemplate', foreach: items }\"></div>";
+
+ // Bind against array, referencing an observable property
+ var myItem = { name: ko.observable("a") };
+ ko.applyBindings({ items: [myItem] });
+ expect(testNode.childNodes[0]).toContainHtml("<div>a</div>");
+
+ // Modify the observable property and check that UI is updated
+ // Previously with the bug, it wasn't updated because the removal of the memo comment caused the array-to-DOM-node computed to be disposed
+ myItem.name("b");
+ expect(testNode.childNodes[0]).toContainHtml("<div>b</div>");
+ });
+
it('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>" }));
@@ -63,7 +63,7 @@
// of which nodes would be deleted if valueToMap was itself later removed
mappedNodes.splice(0, mappedNodes.length);
ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
- }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
+ }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return !ko.utils.anyDomNodeIsAttachedToDocument(mappedNodes); } });
return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
}
View
@@ -208,6 +208,10 @@ ko.utils = new (function () {
return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
},
+ anyDomNodeIsAttachedToDocument: function(nodes) {
+ return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);
+ },
+
tagNameLower: function(element) {
// For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
// Possible future optimization: If we know it's an element from an XHTML document (not HTML),

0 comments on commit b22cd76

Please sign in to comment.