Skip to content

Instantly share code, notes, and snippets.

@rtablada rtablada/01.md Secret
Created Jul 23, 2019

Embed
What would you like to do?

A Mission for More Declarative Component Lookup/Composition

Right now the component helper performs double duty, it does component lookup and component attr composition. This adds a complexity layer that can be hard to understand and does not mesh well with the more declaritive and clear path that Ember is going down.

Also while component does let multiple layers of composition, it can be unclear if a new component lookup is being performed vs if a component is being composed. For this example see the templates below.

Now, here are some thoughts that I've had on some ways this may be clarified...

Component Composition

Most uses of the component helper (at least in my experience in apps and training) has been as a composition mechanism for either yielded components, reusability, or other contextual bindings.

One possiblity would be to have a new compose-component helper (maybe just compose?) that allows composition of component args using import components rather than lookup via string.

Original

In this example a Drop component is composed from the ui/dropdown component in the component registry and then the onchange attr is set to a local method in the current component.

{{yield (hash 
  Drop=(component "ui/dropdown" 
    onchange=(action this.someLocalContextAction)
  )
}}

With compose-component helper (and SFC or other imports)

In this example the Dropdown variable is the component definition for ui/dropdown which has been imported into the current scope (or this could even be the result from another compose-component call!).

{{yield (hash 
  Drop=(compose-component Dropdown
    onchange=(action this.someLocalContextAction)
  )
}}

Dynamic Component lookup

This is a rarer usecase, but it isn't completely solved by an import system without new syntax or best practices. In this example we are looking up a component based on the @myComp attr.

Original:

{{yield (hash Drop=(component @myComp))}}

Using a new component-directory helper for lookup of all components:

The component-directory helper returns a dictionary of all registered components. Therefore using get and the component-directory helpers in combination would result in a functionally identical behavior as string lookup with the component helper today.

However, one note is that this does not compose attrs for the component, for that you will need to use compose-component as listed above.

{{yield (hash Drop=(get (component-directory) @myComp))}}

Using imports and get to narrow the possible components to be composed

Imagine some import for UiDropDown and UiButton in HBS or JS 👋🏽. For this example we are limiting the options to dropdown and button. While, this seems like a reduction in flexibility it actually is a better contract since if combined with compositional components (see the compose-component helper above), then many arbitrary options would not be valid.

{{#let "dropdown" as |myComp|}}
  {{yield (hash Drop=(get (hash dropdown=UiDropDown button=UiButton) @myComp))}}
{{/let}}
<h1>Components!</h1>
<h2>Before</h2>
{{#let (component "my-component") as |MyComp|}}
<MyComp @label="Renamed" @user="Ryan"/>
{{/let}}
{{#let (component "my-component" user="Tom") as |MyComp|}}
<MyComp @label="Composed"/>
<MyComp @label="Composed with override user" @user="Yehuda"/>
{{#let (component MyComp user="Rob") as |Double|}}
<Double @label="Double Composed"/>
<MyComp @label="Composed but in second let"/>
{{/let}}
{{/let}}
<h2>After</h2>
{{#let MyComponent as |MyComp|}}
<MyComp @label="Renamed" @user="Ryan"/>
{{/let}}
{{#let (compose-component MyComponent user="Tom") as |MyComp|}}
<MyComp @label="Composed"/>
<MyComp @label="Composed with override user" @user="Yehuda"/>
{{#let (compose-component MyComp user="Rob") as |Double|}}
<Double @label="Double Composed"/>
<MyComp @label="Composed but in second let"/>
{{/let}}
{{/let}}
<p>Label: {{@label}}</p>
<p>User: {{@user}}</p>
<hr>
@locks

This comment has been minimized.

Copy link

commented Jul 24, 2019

I think it's be more interesting to anchor this idea in the template imports world!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.