diff --git a/packages/ember-htmlbars/lib/hooks/component.js b/packages/ember-htmlbars/lib/hooks/component.js index 927052f1656..fe589b35b5f 100644 --- a/packages/ember-htmlbars/lib/hooks/component.js +++ b/packages/ember-htmlbars/lib/hooks/component.js @@ -12,6 +12,7 @@ import { COMPONENT_HASH, isComponentCell, mergeInNewHash, + processPositionalParamsFromCell, } from 'ember-htmlbars/keywords/closure-component'; var IS_ANGLE_CACHE = new Cache(1000, function(key) { @@ -33,6 +34,21 @@ export default function componentHook(renderNode, env, scope, _tagName, params, let componentCell = stream.value(); if (isComponentCell(componentCell)) { tagName = componentCell[COMPONENT_PATH]; + + /* + * Processing positional params before merging into a hash must be done + * here to avoid problems with rest positional parameters rendered using + * the dot notation. + * + * Closure components (for the contextual component feature) do not + * actually keep the positional params, but process them at each level. + * Therefore, when rendering a closure component with the component + * helper we process the parameters and attributes and then merge those + * on top of the closure component attributes. + * + */ + processPositionalParamsFromCell(componentCell, params, attrs); + params = []; attrs = mergeInNewHash(componentCell[COMPONENT_HASH], attrs); } } diff --git a/packages/ember-htmlbars/lib/keywords/closure-component.js b/packages/ember-htmlbars/lib/keywords/closure-component.js index 79a76687f1f..3c53d273435 100644 --- a/packages/ember-htmlbars/lib/keywords/closure-component.js +++ b/packages/ember-htmlbars/lib/keywords/closure-component.js @@ -74,19 +74,23 @@ export function isComponentCell(component) { } function createNestedClosureComponentCell(componentCell, params, hash) { - let positionalParams = componentCell[COMPONENT_POSITIONAL_PARAMS]; - // This needs to be done in each nesting level to avoid raising assertions - processPositionalParams(null, positionalParams, params, hash); + processPositionalParamsFromCell(componentCell, params, hash); return { [COMPONENT_PATH]: componentCell[COMPONENT_PATH], [COMPONENT_HASH]: mergeInNewHash(componentCell[COMPONENT_HASH], hash), - [COMPONENT_POSITIONAL_PARAMS]: positionalParams, + [COMPONENT_POSITIONAL_PARAMS]: componentCell[COMPONENT_POSITIONAL_PARAMS], [COMPONENT_CELL]: true }; } +export function processPositionalParamsFromCell(componentCell, params, hash) { + let positionalParams = componentCell[COMPONENT_POSITIONAL_PARAMS]; + + processPositionalParams(null, positionalParams, params, hash); +} + function createNewClosureComponentCell(env, componentPath, params, hash) { let positionalParams = getPositionalParams(env.owner, componentPath); diff --git a/packages/ember-htmlbars/lib/keywords/element-component.js b/packages/ember-htmlbars/lib/keywords/element-component.js index 8878e4c61b6..84b9556cec6 100644 --- a/packages/ember-htmlbars/lib/keywords/element-component.js +++ b/packages/ember-htmlbars/lib/keywords/element-component.js @@ -1,12 +1,11 @@ import assign from 'ember-metal/assign'; import { COMPONENT_PATH, - COMPONENT_POSITIONAL_PARAMS, COMPONENT_HASH, isComponentCell, mergeInNewHash, + processPositionalParamsFromCell, } from './closure-component'; -import { processPositionalParams } from 'ember-htmlbars/utils/extract-positional-params'; export default { setupState(lastState, env, scope, params, hash) { @@ -58,10 +57,9 @@ function render(morph, env, scope, [path, ...params], hash, template, inverse, v if (isComponentCell(path)) { let closureComponent = env.hooks.getValue(path); - let positionalParams = closureComponent[COMPONENT_POSITIONAL_PARAMS]; // This needs to be done in each nesting level to avoid raising assertions - processPositionalParams(null, positionalParams, params, hash); + processPositionalParamsFromCell(closureComponent, params, hash); params = []; hash = mergeInNewHash(closureComponent[COMPONENT_HASH], hash); } diff --git a/packages/ember-htmlbars/lib/utils/extract-positional-params.js b/packages/ember-htmlbars/lib/utils/extract-positional-params.js index bc412c6adb4..8747920396b 100644 --- a/packages/ember-htmlbars/lib/utils/extract-positional-params.js +++ b/packages/ember-htmlbars/lib/utils/extract-positional-params.js @@ -11,9 +11,9 @@ export default function extractPositionalParams(renderNode, component, params, a } export function processPositionalParams(renderNode, positionalParams, params, attrs) { - let isNamed = typeof positionalParams === 'string'; + let isRest = typeof positionalParams === 'string'; - if (isNamed) { + if (isRest) { processRestPositionalParameters(renderNode, positionalParams, params, attrs); } else { processNamedPositionalParameters(renderNode, positionalParams, params, attrs); diff --git a/packages/ember-htmlbars/tests/helpers/closure_component_test.js b/packages/ember-htmlbars/tests/helpers/closure_component_test.js index 5b3c37ef7e9..dde15a187f1 100644 --- a/packages/ember-htmlbars/tests/helpers/closure_component_test.js +++ b/packages/ember-htmlbars/tests/helpers/closure_component_test.js @@ -429,6 +429,33 @@ if (isEnabled('ember-contextual-components')) { equal(component.$().text(), expectedText, '-looked-up component rendered'); }); + QUnit.test('renders with dot path and with rest positional parameters', function() { + let LookedUp = Component.extend(); + LookedUp.reopenClass({ + positionalParams: 'params' + }); + owner.register( + 'component:-looked-up', + LookedUp + ); + let expectedText = 'Hodi'; + owner.register( + 'template:components/-looked-up', + compile('{{params}}') + ); + + let template = compile('{{#with (hash lookedup=(component "-looked-up")) as |object|}}{{object.lookedup expectedText "Hola"}}{{/with}}'); + component = Component.extend({ + [OWNER]: owner, + template + }).create({ + expectedText + }); + + runAppend(component); + equal(component.$().text(), `${expectedText},Hola`, '-looked-up component rendered with rest params'); + }); + QUnit.test('adding parameters to a closure component\'s instance does not add it to other instances', function(assert) { owner.register( 'template:components/select-box',