diff --git a/spec/defaultBindings/withBehaviors.js b/spec/defaultBindings/withBehaviors.js index cf80eef57..a9df2293b 100644 --- a/spec/defaultBindings/withBehaviors.js +++ b/spec/defaultBindings/withBehaviors.js @@ -224,7 +224,6 @@ describe('Binding: With', function() { model.items()[0].x(10); expect(testNode).toContainText("Total: 25"); }); -}); it('Should call an afterRender callback function and not cause updates if an observable accessed in the callback is changed', function () { testNode.innerHTML = "
"; @@ -240,12 +239,31 @@ describe('Binding: With', function() { // Update callback observable and check that the binding wasn't updated callbackObservable(2); expect(testNode.childNodes[0]).toContainText('child'); - // Update the observableArray and verify that the binding is now updated + // Update the observable and verify that the binding is now updated someItem({ childprop: 'new child' }); expect(testNode.childNodes[0]).toContainText('new child'); expect(callbacks).toEqual(2); }); + it('Should call an afterRender callback function when bound to a virtual element', function () { + testNode.innerHTML = ""; + var someItem = ko.observable({ childprop: 'child' }), + callbacks = 0; + var callback = function (nodes, data) { + expect(nodes.length).toEqual(1); + expect(nodes[0]).toEqual(testNode.childNodes[1]); + expect(data.childprop).toEqual(someItem().childprop); + callbacks++; + }; + ko.applyBindings({ someItem: someItem, callback: callback }, testNode); + expect(callbacks).toEqual(1); + + // Update the observable and verify that the binding is now updated + someItem({ childprop: 'new child' }); + expect(testNode.childNodes[1]).toContainText('new child'); + expect(callbacks).toEqual(2); + }); + it('Should not call an afterRender callback function when data gets cleared', function () { testNode.innerHTML = "
"; var someItem = ko.observable({ childprop: 'child' }), diff --git a/src/binding/defaultBindings/ifIfnotWith.js b/src/binding/defaultBindings/ifIfnotWith.js index f68e747dc..3d1a39aff 100755 --- a/src/binding/defaultBindings/ifIfnotWith.js +++ b/src/binding/defaultBindings/ifIfnotWith.js @@ -10,16 +10,17 @@ function makeWithIfBinding(bindingKey, isWith, isNot) { ko.computed(function() { var rawWithValue = isWith && ko.utils.unwrapObservable(valueAccessor()), shouldDisplay = isWith ? !!rawWithValue : ifCondition(), - isFirstRender = !savedNodes; + isFirstRender = !savedNodes, + renderNodes; // Save a copy of the inner nodes on the initial update, but only if we have dependencies. if (isFirstRender && ko.computedContext.getDependenciesCount()) { - savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */); + savedNodes = ko.utils.cloneNodes(renderNodes = ko.virtualElements.childNodes(element), true /* shouldCleanNodes */); } if (shouldDisplay) { if (!isFirstRender) { - ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes)); + ko.virtualElements.setDomNodeChildren(element, renderNodes = ko.utils.cloneNodes(savedNodes)); } var newContext = isWith ? bindingContext['createChildContext'](typeof rawWithValue == "function" ? rawWithValue : valueAccessor) : @@ -27,8 +28,8 @@ function makeWithIfBinding(bindingKey, isWith, isNot) { bindingContext['extend'](function() { ifCondition(); return null; }) : bindingContext; ko.applyBindingsToDescendants(newContext, element); - if (element.childNodes.length && allBindings.has('afterRender')) { - ko.dependencyDetection.ignore(allBindings.get('afterRender'), null, [element.childNodes, newContext['$data']]); + if (allBindings.has('afterRender')) { + ko.dependencyDetection.ignore(allBindings.get('afterRender'), null, [renderNodes || ko.virtualElements.childNodes(element), newContext['$data']]); } } else { ko.virtualElements.emptyNode(element);