Skip to content

Commit

Permalink
Merge pull request knockout#739 from SteveSanderson/739-foreach-with-…
Browse files Browse the repository at this point in the history
…template-rewriting-bugfix

jquery.tmpl interpolation of observables are not updated when inside data-bind'ed elements
  • Loading branch information
mbest committed Dec 4, 2012
2 parents b1076c4 + 6205bf5 commit b22cd76
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 1 deletion.
18 changes: 18 additions & 0 deletions spec/templatingBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -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>" }));
Expand Down
2 changes: 1 addition & 1 deletion src/binding/editDetection/arrayToDomNodeChildren.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) };
}

Expand Down
4 changes: 4 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down

0 comments on commit b22cd76

Please sign in to comment.