Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/yjo/knockout into 1415-wi…
Browse files Browse the repository at this point in the history
…th-rawdata
  • Loading branch information
mbest committed Nov 19, 2015
2 parents de2cac6 + 6d5678f commit 2161ce0
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 7 deletions.
16 changes: 16 additions & 0 deletions spec/defaultBindings/withBehaviors.js
Expand Up @@ -176,4 +176,20 @@ describe('Binding: With', function() {
viewModel.topitem(null);
expect(testNode).toContainHtml("hello <!-- ko with: topitem --><!-- /ko -->");
});

it('Should provide access to an observable viewModel through $rawData', function() {
testNode.innerHTML = "<div data-bind='with: item'><input data-bind='value: $rawData'/></div>";
var item = ko.observable('one');
ko.applyBindings({ item: item }, testNode);
expect(testNode.childNodes[0]).toHaveValues(['one']);

// Should update observable when input is changed
testNode.childNodes[0].childNodes[0].value = 'two';
ko.utils.triggerEvent(testNode.childNodes[0].childNodes[0], "change");
expect(item()).toEqual('two');

// Should update the input when the observable changes
item('three');
expect(testNode.childNodes[0]).toHaveValues(['three']);
});
});
16 changes: 16 additions & 0 deletions spec/templatingBehaviors.js
Expand Up @@ -385,6 +385,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
2 changes: 1 addition & 1 deletion src/binding/defaultBindings/ifIfnotWith.js
Expand Up @@ -20,7 +20,7 @@ function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
if (!isFirstRender) {
ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));
}
ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, valueAccessor) : bindingContext, element);
} else {
ko.virtualElements.emptyNode(element);
}
Expand Down
17 changes: 11 additions & 6 deletions src/templating/templating.js
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 @@ -245,7 +250,6 @@
},
'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor(),
dataValue,
options = ko.utils.unwrapObservable(value),
shouldDisplay = true,
templateComputed = null,
Expand All @@ -263,7 +267,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 @@ -275,7 +280,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 2161ce0

Please sign in to comment.