Skip to content

Commit

Permalink
Add $component to represent closest component viewmodel in binding co…
Browse files Browse the repository at this point in the history
…ntexts
  • Loading branch information
SteveSanderson committed Oct 17, 2014
1 parent 96aa912 commit 49747f2
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 4 deletions.
26 changes: 26 additions & 0 deletions spec/components/componentBindingBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,32 @@ describe('Components: Component binding', function() {
expect(testNode.childNodes[0]).toContainHtml('start<span data-bind="template: { nodes: $componenttemplatenodes }"><em>original</em> child nodes</span>end');
});

it('Creates a binding context with $component to reference the closest component viewmodel', function() {
this.after(function() {
ko.components.unregister('sub-component');
});

ko.components.register(testComponentName, {
template: '<span data-bind="with: { childContext: 123 }">'
+ 'In child context <!-- ko text: childContext --><!-- /ko -->, '
+ 'inside component with property <!-- ko text: $component.componentProp --><!-- /ko -->. '
+ '<div data-bind="component: \'sub-component\'"></div>'
+ '</span>',
viewModel: function() { return { componentProp: 456 }; }
});

// See it works with nesting - $component always refers to the *closest* component root
ko.components.register('sub-component', {
template: 'Now in sub-component with property <!-- ko text: $component.componentProp --><!-- /ko -->.',
viewModel: function() { return { componentProp: 789 }; }
});

ko.applyBindings(outerViewModel, testNode);
jasmine.Clock.tick(1);

expect(testNode.childNodes[0]).toContainText('In child context 123, inside component with property 456. Now in sub-component with property 789.');
});

it('Passes nonobservable params to the component', function() {
// Set up a component that logs its constructor params
var receivedParams = [];
Expand Down
11 changes: 7 additions & 4 deletions spec/components/customElementBehaviors.js
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,12 @@ describe('Components: Custom elements', function() {

// First define a reusable 'special-list' component that produces a <ul> in which the <li>s have special CSS classes
// It also injects and binds a supplied template for each list item
// Note: It would be even simpler to write "template: { nodes: $componentTemplateNodes }", which would also work.
// However it's useful to have test coverage for the more longwinded approach of passing nodes via your
// viewmodel as well, so retaining the longer syntax for this test.
ko.components.register('special-list', {
template: '<ul class="my-special-list" data-bind="foreach: specialListItems">'
+ '<li class="special-list-item" data-bind="template: { nodes: $parent.suppliedItemTemplate }">'
+ '<li class="special-list-item" data-bind="template: { nodes: $component.suppliedItemTemplate }">'
+ '</li>'
+ '</ul>',
viewModel: {
Expand Down Expand Up @@ -444,13 +447,13 @@ describe('Components: Custom elements', function() {
expect(testNode.childNodes[1].childNodes[0].tagName.toLowerCase()).toEqual('ul');
expect(testNode.childNodes[1].childNodes[0].className).toEqual('my-special-list');
expect(testNode.childNodes[1].childNodes[0]).toContainHtml(
'<li class="special-list-item" data-bind="template: { nodes: $parent.supplieditemtemplate }">'
'<li class="special-list-item" data-bind="template: { nodes: $component.supplieditemtemplate }">'
+ '<em data-bind="text: name">brie</em> has quality <em data-bind="text: quality">7</em>'
+ '</li>'
+ '<li class="special-list-item" data-bind="template: { nodes: $parent.supplieditemtemplate }">'
+ '<li class="special-list-item" data-bind="template: { nodes: $component.supplieditemtemplate }">'
+ '<em data-bind="text: name">cheddar</em> has quality <em data-bind="text: quality">9</em>'
+ '</li>'
+ '<li class="special-list-item" data-bind="template: { nodes: $parent.supplieditemtemplate }">'
+ '<li class="special-list-item" data-bind="template: { nodes: $component.supplieditemtemplate }">'
+ '<em data-bind="text: name">roquefort</em> has quality <em data-bind="text: quality">3</em>'
+ '</li>'
);
Expand Down
1 change: 1 addition & 0 deletions src/components/componentBinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
cloneTemplateIntoElement(componentName, componentDefinition, element);
var componentViewModel = createViewModel(componentDefinition, element, originalChildNodes, componentParams),
childBindingContext = bindingContext['createChildContext'](componentViewModel, /* dataItemAlias */ undefined, function(ctx) {
ctx['$component'] = componentViewModel;
ctx['$componentTemplateNodes'] = originalChildNodes;
});
currentViewModel = componentViewModel;
Expand Down

0 comments on commit 49747f2

Please sign in to comment.