Skip to content

Commit

Permalink
Ensure afterRender is always called with the template's data value (e…
Browse files Browse the repository at this point in the history
…ven if $data isn't set)
  • Loading branch information
mbest committed May 24, 2018
1 parent 5134029 commit 02ce9fd
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 10 deletions.
30 changes: 30 additions & 0 deletions spec/defaultBindings/foreachBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,21 @@ describe('Binding: Foreach', function() {
expect(testNode.childNodes[0]).toContainText('second');
expect(testNode.childNodes[0].childNodes[0]).toEqual(saveNode);
});

it('Should call an afterRender callback function with the array item', function () {
testNode.innerHTML = "<div data-bind='foreach: { data: someItems, as: \"item\", afterRender: callback }'>[<span data-bind='text: item'></span>]</div>";
var someItems = ko.observableArray(['Alpha', 'Beta']),
callbackReceivedArrayValues = [];
ko.applyBindings({
someItems: someItems,
callback: function(nodes, arrayValue) {
callbackReceivedArrayValues.push(arrayValue);
}
}, testNode);

expect(testNode.childNodes[0]).toContainText('[Alpha][Beta]');
expect(callbackReceivedArrayValues).toEqual(['Alpha', 'Beta']);
});
});

describe('With "createChildContextWithAs = true" and "as"', function () {
Expand Down Expand Up @@ -797,5 +812,20 @@ describe('Binding: Foreach', function() {
expect(testNode.childNodes[0]).toContainText('second');
expect(testNode.childNodes[0].childNodes[0]).toEqual(saveNode);
});

it('Should call an afterRender callback function with the array item', function () {
testNode.innerHTML = "<div data-bind='foreach: { data: someItems, as: \"item\", afterRender: callback }'>[<span data-bind='text: item'></span>]</div>";
var someItems = ko.observableArray(['Alpha', 'Beta']),
callbackReceivedArrayValues = [];
ko.applyBindings({
someItems: someItems,
callback: function(nodes, arrayValue) {
callbackReceivedArrayValues.push(arrayValue);
}
}, testNode);

expect(testNode.childNodes[0]).toContainText('[Alpha][Beta]');
expect(callbackReceivedArrayValues).toEqual(['Alpha', 'Beta']);
});
});
});
69 changes: 60 additions & 9 deletions spec/templatingBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1013,15 +1013,6 @@ describe('Templating', function() {
expect(testNode.childNodes[0]).toContainText("Alternative output");
});

it('Should be able to bind $data to an alias using \'as\'', function() {
ko.setTemplateEngine(new dummyTemplateEngine({
myTemplate: "ValueLiteral: [js:item.prop], ValueBound: <span data-bind='text: item.prop'></span>"
}));
testNode.innerHTML = "<div data-bind='template: { name: \"myTemplate\", data: someItem, as: \"item\" }'></div>";
ko.applyBindings({ someItem: { prop: 'Hello' } }, testNode);
expect(testNode.childNodes[0]).toContainText("ValueLiteral: Hello, ValueBound: Hello");
});

it('Data-bind syntax should expose parent binding context as $parent if binding with an explicit \"data\" value', function() {
ko.setTemplateEngine(new dummyTemplateEngine({
myTemplate: "ValueLiteral: [js:$parent.parentProp], ValueBound: <span data-bind='text: $parent.parentProp'></span>"
Expand Down Expand Up @@ -1187,4 +1178,64 @@ describe('Templating', function() {
expect(testDocFrag.childNodes[0].tagName).toEqual("P");
expect(testDocFrag.childNodes[0]).toContainHtml("myval: 123");
});

describe('With "createChildContextWithAs = false" and "as"', function () {
beforeEach(function() {
this.restoreAfter(ko.options, 'createChildContextWithAs');
ko.options.createChildContextWithAs = false;
});

it('Should bind viewmodel to an alias', function() {
ko.setTemplateEngine(new dummyTemplateEngine({
myTemplate: "ValueLiteral: [js:item.prop], ValueBound: <span data-bind='text: item.prop'></span>"
}));
testNode.innerHTML = "<div data-bind='template: { name: \"myTemplate\", data: someItem, as: \"item\" }'></div>";
ko.applyBindings({ someItem: { prop: 'Hello' } }, testNode);
expect(testNode.childNodes[0]).toContainText("ValueLiteral: Hello, ValueBound: Hello");
});

it('Should call \'afterRender\' callback with the viewmodel', function () {
var passedDataItem;
var myCallback = function(elementsArray, dataItem) {
passedDataItem = dataItem;
}
var myModel = { prop: 'Hello' };
ko.setTemplateEngine(new dummyTemplateEngine({
myTemplate: "ValueLiteral: [js:item.prop], ValueBound: <span data-bind='text: item.prop'></span>"
}));
testNode.innerHTML = "<div data-bind='template: { name: \"myTemplate\", data: someItem, as: \"item\", afterRender: callback }'></div>";
ko.applyBindings({ someItem: myModel, callback: myCallback }, testNode);
expect(passedDataItem).toEqual(myModel);
});
});

describe('With "createChildContextWithAs = true" and "as"', function () {
beforeEach(function() {
this.restoreAfter(ko.options, 'createChildContextWithAs');
ko.options.createChildContextWithAs = true;
});

it('Should bind viewmodel to an alias', function() {
ko.setTemplateEngine(new dummyTemplateEngine({
myTemplate: "ValueLiteral: [js:item.prop], ValueBound: <span data-bind='text: item.prop'></span>"
}));
testNode.innerHTML = "<div data-bind='template: { name: \"myTemplate\", data: someItem, as: \"item\" }'></div>";
ko.applyBindings({ someItem: { prop: 'Hello' } }, testNode);
expect(testNode.childNodes[0]).toContainText("ValueLiteral: Hello, ValueBound: Hello");
});

it('Should call \'afterRender\' callback with the viewmodel', function () {
var passedDataItem;
var myCallback = function(elementsArray, dataItem) {
passedDataItem = dataItem;
}
var myModel = { prop: 'Hello' };
ko.setTemplateEngine(new dummyTemplateEngine({
myTemplate: "ValueLiteral: [js:item.prop], ValueBound: <span data-bind='text: item.prop'></span>"
}));
testNode.innerHTML = "<div data-bind='template: { name: \"myTemplate\", data: someItem, as: \"item\", afterRender: callback }'></div>";
ko.applyBindings({ someItem: myModel, callback: myCallback }, testNode);
expect(passedDataItem).toEqual(myModel);
});
});
});
2 changes: 1 addition & 1 deletion src/templating/templating.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
if (haveAddedNodesToParent) {
activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
if (options['afterRender']) {
ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext[options['as'] || '$data']]);
}
if (renderMode == "replaceChildren") {
ko.bindingEvent.notify(targetNodeOrNodeArray, ko.bindingEvent.childrenComplete);
Expand Down

0 comments on commit 02ce9fd

Please sign in to comment.