Skip to content

Commit

Permalink
Allow direct reference to an observable view model within a rendered …
Browse files Browse the repository at this point in the history
…template using $rawData
  • Loading branch information
Joe Lee-Moyet authored and Joe Lee-Moyet committed Sep 17, 2014
1 parent d59a69a commit 6d5678f
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 6 deletions.
16 changes: 16 additions & 0 deletions spec/templatingBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,22 @@ describe('Templating', function() {
expect(testNode.childNodes[0]).toContainText("true");
});

it('Data binding syntax should be able to use $rawData in binding value to refer to a top level template\'s view model observable', function() {
ko.setTemplateEngine(new dummyTemplateEngine({ someTemplate: "<div data-bind='text: ko.isObservable($rawData)'></div>" }));
ko.renderTemplate("someTemplate", ko.observable('value'), null, testNode);
expect(testNode.childNodes[0]).toContainText("true");
});

it('Data binding syntax should be able to use $rawData in binding value to refer to a data-bound template\'s view model observable', function() {
ko.setTemplateEngine(new dummyTemplateEngine({ someTemplate: "<div data-bind='text: ko.isObservable($rawData)'></div>" }));
testNode.innerHTML = "<div data-bind='template: { name: \"someTemplate\", data: someProp }'></div>";

viewModel = { someProp: ko.observable('value') };
ko.applyBindings(viewModel, testNode);

expect(testNode.childNodes[0].childNodes[0]).toContainText("true");
});

it('Data binding syntax should defer evaluation of variables until the end of template rendering (so bindings can take independent subscriptions to them)', function () {
ko.setTemplateEngine(new dummyTemplateEngine({
someTemplate: "<input data-bind='value:message' />[js: message = 'goodbye'; undefined; ]"
Expand Down
17 changes: 11 additions & 6 deletions src/templating/templating.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,14 @@
return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
function () {
// Ensure we've got a proper binding context to work with
var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
? dataOrBindingContext
: new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
var bindingContext;
if (dataOrBindingContext instanceof ko.bindingContext) {
bindingContext = dataOrBindingContext;
} else {
// Create dependency so that a new context is created when data updates
ko.utils.unwrapObservable(dataOrBindingContext);
bindingContext = new ko.bindingContext(dataOrBindingContext);
}

var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext),
renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
Expand Down Expand Up @@ -234,7 +239,6 @@
},
'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor(),
dataValue,
options = ko.utils.unwrapObservable(value),
shouldDisplay = true,
templateComputed = null,
Expand All @@ -252,7 +256,8 @@
if (shouldDisplay && 'ifnot' in options)
shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);

dataValue = ko.utils.unwrapObservable(options['data']);
// Create dependency on template view model to re-render when it mutates:
ko.utils.unwrapObservable(options['data']);
}

if ('foreach' in options) {
Expand All @@ -264,7 +269,7 @@
} else {
// Render once for this single data point (or use the viewModel if no data was provided)
var innerBindingContext = ('data' in options) ?
bindingContext['createChildContext'](dataValue, options['as']) : // Given an explitit 'data' value, we create a child binding context for it
bindingContext['createChildContext'](options['data'], options['as']) : // Given an explitit 'data' value, we create a child binding context for it
bindingContext; // Given no explicit 'data' value, we retain the same binding context
templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
}
Expand Down

0 comments on commit 6d5678f

Please sign in to comment.