Skip to content

Commit

Permalink
Add spec about $rawData value in extended context when binding to a f…
Browse files Browse the repository at this point in the history
…unction that returns an observable view model.
  • Loading branch information
mbest committed Feb 9, 2014
1 parent ea06bdd commit f5832fd
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
36 changes: 34 additions & 2 deletions spec/bindingDependencyBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ describe('Binding dependencies', function() {

it('Should update all extended contexts (including values copied from the parent)', function() {
ko.bindingHandlers.withProperties = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var innerBindingContext = bindingContext.extend(valueAccessor);
ko.applyBindingsToDescendants(innerBindingContext, element);
return { controlsDescendantBindings : true };
Expand All @@ -368,9 +368,41 @@ describe('Binding dependencies', function() {
expect(vm.getSubscriptionsCount()).toEqual(0);
});

it('Should maintain correct $rawData in extended context when parent is bound to a function that returns an observable view model', function() {
ko.bindingHandlers.extended = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
ko.applyBindingsToDescendants(bindingContext.extend(valueAccessor), element);
return { controlsDescendantBindings : true };
}
};

var vm1 = ko.observable('vm1'),
vm2 = ko.observable('vm2'),
whichVm = ko.observable(vm1);
testNode.innerHTML = "<div data-bind='extended: {}'><div data-bind='text: $data'></div></div>";
ko.applyBindings(function() { return whichVm(); }, testNode);
expect(testNode).toContainText('vm1');

var parentContext = ko.contextFor(testNode),
childContext = ko.contextFor(testNode.childNodes[0].childNodes[0]);

expect(parentContext.$data).toEqual('vm1');
expect(parentContext.$rawData).toBe(vm1);

expect(childContext).not.toBe(parentContext);
expect(childContext.$data).toEqual('vm1');
expect(childContext.$rawData).toBe(vm1);

// Updating view model updates bindings and context
whichVm(vm2);
expect(testNode).toContainText('vm2');
expect(childContext.$data).toEqual('vm2');
expect(childContext.$rawData).toBe(vm2);
});

it('Should update an extended child context', function() {
ko.bindingHandlers.withProperties = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var childBindingContext = bindingContext.createChildContext(null, null, function(context) {
ko.utils.extend(context, valueAccessor());
});
Expand Down
2 changes: 2 additions & 0 deletions src/binding/bindingAttributeSyntax.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@
// Similarly to "child" contexts, provide a function here to make sure that the correct values are set
// when an observable view model is updated.
ko.bindingContext.prototype['extend'] = function(properties) {
// If the parent context references an observable view model, "_subscribable" will always be the
// latest view model object. If not, "_subscribable" isn't set, and we can use the static "$data" value.
return new ko.bindingContext(this._subscribable || this['$data'], this, null, function(self, parentContext) {
// This "child" context doesn't directly track a parent observable view model,
// so we need to manually set the $rawData value to match the parent.
Expand Down

0 comments on commit f5832fd

Please sign in to comment.