From 2d128dbd4adba409312c6f3b642d06067c89d5d7 Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Tue, 19 May 2015 11:12:40 -0400 Subject: [PATCH] [BUGFIX beta] Allows for an arbitrary # of positional parameters When the `positionalParams` property on a component is a string, the positional parameters passed to the component will be an array that is bound to that attribute, as per requested by @rwjblue here: https://github.com/emberjs/ember.js/pull/11028#issuecomment-101029926 --- .../node-managers/component-node-manager.js | 26 ++++++-- .../integration/component_invocation_test.js | 60 ++++++++++++++++--- 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/packages/ember-htmlbars/lib/node-managers/component-node-manager.js b/packages/ember-htmlbars/lib/node-managers/component-node-manager.js index 222d329823d..315ec8d1bf6 100644 --- a/packages/ember-htmlbars/lib/node-managers/component-node-manager.js +++ b/packages/ember-htmlbars/lib/node-managers/component-node-manager.js @@ -10,6 +10,8 @@ import { MUTABLE_CELL } from "ember-views/compat/attrs-proxy"; import SafeString from "htmlbars-util/safe-string"; import { instrument } from "ember-htmlbars/system/instrumentation-support"; import EmberComponent from "ember-views/views/component"; +import Stream from 'ember-metal/streams/stream'; +import { readArray } from 'ember-metal/streams/utils'; // In theory this should come through the env, but it should // be safe to import this until we make the hook system public @@ -89,10 +91,26 @@ function extractPositionalParams(renderNode, component, params, attrs) { // if the component is rendered via {{component}} helper, the first // element of `params` is the name of the component, so we need to // skip that when the positional parameters are constructed - let paramsStartIndex = renderNode.state.isComponentHelper ? 1 : 0; - let pp = component.positionalParams; - for (let i=0; i { + return readArray(params.slice(paramsStartIndex)); + }, 'params'); + + attrs[positionalParams] = paramsStream; + } + + for (let i=0; i < positionalParams.length; i++) { + let param = params[paramsStartIndex + i]; + if (isNamed) { + paramsStream.addDependency(param); + } else { + attrs[positionalParams[i]] = param; + } } } } diff --git a/packages/ember-htmlbars/tests/integration/component_invocation_test.js b/packages/ember-htmlbars/tests/integration/component_invocation_test.js index 665a3ef3f56..7165f50f330 100644 --- a/packages/ember-htmlbars/tests/integration/component_invocation_test.js +++ b/packages/ember-htmlbars/tests/integration/component_invocation_test.js @@ -6,6 +6,7 @@ import ComponentLookup from 'ember-views/component_lookup'; import Component from "ember-views/views/component"; import { runAppend, runDestroy } from "ember-runtime/tests/utils"; import { get } from "ember-metal/property_get"; +import { set } from "ember-metal/property_set"; import run from "ember-metal/run_loop"; var registry, container, view; @@ -258,7 +259,7 @@ if (Ember.FEATURES.isEnabled('ember-views-component-block-info')) { }); } -QUnit.test('static positional parameters', function() { +QUnit.test('static named positional parameters', function() { registry.register('template:components/sample-component', compile('{{attrs.name}}{{attrs.age}}')); registry.register('component:sample-component', Component.extend({ positionalParams: ['name', 'age'] @@ -274,7 +275,7 @@ QUnit.test('static positional parameters', function() { equal(jQuery('#qunit-fixture').text(), 'Quint4'); }); -QUnit.test('dynamic positional parameters', function() { +QUnit.test('dynamic named positional parameters', function() { registry.register('template:components/sample-component', compile('{{attrs.name}}{{attrs.age}}')); registry.register('component:sample-component', Component.extend({ positionalParams: ['name', 'age'] @@ -292,13 +293,58 @@ QUnit.test('dynamic positional parameters', function() { runAppend(view); equal(jQuery('#qunit-fixture').text(), 'Quint4'); run(function() { - Ember.set(view.context, 'myName', 'Edward'); - Ember.set(view.context, 'myAge', '5'); + set(view.context, 'myName', 'Edward'); + set(view.context, 'myAge', '5'); }); equal(jQuery('#qunit-fixture').text(), 'Edward5'); }); +QUnit.test('static arbitrary number of positional parameters', function() { + registry.register('template:components/sample-component', compile('{{#each attrs.names as |name|}}{{name}}{{/each}}')); + registry.register('component:sample-component', Component.extend({ + positionalParams: 'names' + })); + + view = EmberView.extend({ + layout: compile('{{sample-component "Foo" 4 "Bar" id="args-3"}}{{sample-component "Foo" 4 "Bar" 5 "Baz" id="args-5"}}{{component "sample-component" "Foo" 4 "Bar" 5 "Baz" id="helper"}}'), + container: container + }).create(); + + runAppend(view); + + equal(view.$('#args-3').text(), 'Foo4Bar'); + equal(view.$('#args-5').text(), 'Foo4Bar5Baz'); + equal(view.$('#helper').text(), 'Foo4Bar5Baz'); +}); + +QUnit.test('dynamic arbitrary number of positional parameters', function() { + registry.register('template:components/sample-component', compile('{{#each attrs.names as |name|}}{{name}}{{/each}}')); + registry.register('component:sample-component', Component.extend({ + positionalParams: 'names' + })); + + view = EmberView.extend({ + layout: compile('{{sample-component user1 user2 id="direct"}}{{component "sample-component" user1 user2 id="helper"}}'), + container: container, + context: { + user1: 'Foo', + user2: 4 + } + }).create(); + + runAppend(view); + equal(view.$('#direct').text(), 'Foo4'); + equal(view.$('#helper').text(), 'Foo4'); + run(function() { + set(view.context, 'user1', 'Bar'); + set(view.context, 'user2', '5'); + }); + + equal(view.$('#direct').text(), 'Bar5'); + equal(view.$('#helper').text(), 'Bar5'); +}); + QUnit.test('moduleName is available on _renderNode when a layout is present', function() { expect(1); @@ -360,8 +406,8 @@ if (Ember.FEATURES.isEnabled('ember-htmlbars-component-helper')) { runAppend(view); equal(jQuery('#qunit-fixture').text(), 'Quint4'); run(function() { - Ember.set(view.context, 'myName', 'Edward'); - Ember.set(view.context, 'myAge', '5'); + set(view.context, 'myName', 'Edward'); + set(view.context, 'myAge', '5'); }); equal(jQuery('#qunit-fixture').text(), 'Edward5'); @@ -382,7 +428,7 @@ QUnit.test('yield to inverse', function() { runAppend(view); equal(jQuery('#qunit-fixture').text(), 'Yes:Hello42'); run(function() { - Ember.set(view.context, 'activated', false); + set(view.context, 'activated', false); }); equal(jQuery('#qunit-fixture').text(), 'No:Goodbye');