-
-
Notifications
You must be signed in to change notification settings - Fork 408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Angle Bracket Invocations For Built-in Components #459
Merged
Merged
Changes from 3 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
2216eec
Angle Bracket Invocations For Built-in Components
chancancode f3b2453
Update text/0459-angle-bracket-built-in-components.md
rwjblue d60495f
Update text/0459-angle-bracket-built-in-components.md
rwjblue d3a0e4d
typo
chancancode 9abd68d
framework core team feedback
chancancode 0ebfbb3
Update 0459-angle-bracket-built-in-components.md
locks 32a25b3
Update text/0459-angle-bracket-built-in-components.md
jenweber File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
- Start Date: 2019-03-05 | ||
- Relevant Team(s): Ember.js | ||
- RFC PR: https://github.com/emberjs/rfcs/pull/459 | ||
- Tracking: (leave this empty) | ||
|
||
# Angle Bracket Invocations For Built-in Components | ||
|
||
## Summary | ||
|
||
[RFC #311](./0311-angle-bracket-invocation.md) introduced the angle bracket | ||
component invocation syntax. Many developers in the Ember community has since | ||
adopted this feature with very positive feedback. This style of component | ||
invocation will beomce the default style in the Octane edition and become the | ||
primary way component invocations are taught. | ||
|
||
However, Ember ships with three built-in components – `{{link-to}}`, `{{input}}` | ||
and `{{textarea}}`. To date, it is not possible to invoke them with the angle | ||
bracket syntax due to various API mismatches and implementation details. | ||
|
||
This RFC proposes some small amendments to these APIs and their implementations | ||
to allow them to be invoked with the angle bracket syntax, i.e. `<LinkTo>`, | ||
`<Input>` and `<TextArea>`. | ||
|
||
## Motivation | ||
|
||
As mentioned above, this will allow Ember developers to invoke components with | ||
a consistent syntax, which should make it easier to teach. | ||
|
||
This RFC _does not_ aim to "fix" issues or quirks with the existing APIs – it | ||
merely attempts to provide a way to do the equivilant invocation in angle | ||
bracket syntax. | ||
|
||
## Detailed design | ||
|
||
### `<LinkTo>` | ||
|
||
There are two main problem with `{{link-to}}`: | ||
|
||
* It uses positional arguments as the main API. | ||
* It supports an "inline" form (i.e. without a block). | ||
|
||
In the new world, components are expected to work with named arguments. This is | ||
both to improve clarity and to match the HTML tags model (which angle bracket | ||
invocations are loosely modelled after). Positional arguments are reserved for | ||
"control-flow-like" components (e.g. `liquid-if`) and to be paired with the | ||
curly bracket invocation style. Since links are not that, it is not appropiate | ||
for this component to use positional params. | ||
|
||
When invoked with a block, the first argument is the route to navigate to. We | ||
propose to name this argument explicitly, with `@route`: | ||
|
||
```hbs | ||
{{#link-to "about"}}About Us{{/link-to}} | ||
|
||
...becomes... | ||
|
||
<LinkTo @route="about">About Us</LinkTo> | ||
``` | ||
|
||
The second argument can be used to provide a model to the route. We propose to | ||
name this argument explicitly, with `@model`: | ||
|
||
```hbs | ||
{{#let this.model.posts.firstObject as |post|}} | ||
|
||
{{#link-to "post" post}}Read {{post.title}}...{{/link-to}} | ||
|
||
...becomes... | ||
|
||
<LinkTo @route="post" @model={{post}}>Read {{post.title}}...</LinkTo> | ||
|
||
{{/let}} | ||
``` | ||
|
||
In fact, it is possible to pass multiple models to deeply nested routes with | ||
additional positional arguments. For this use case, we propose the `@models` | ||
named argument which accepts an array: | ||
|
||
```hbs | ||
{{#let this.model.posts.firstObject as |post|}} | ||
{{#each post.comments as |comment|}} | ||
|
||
{{#link-to "post.comment" post comment}} | ||
Comment by {{comment.author.name}} on {{comment.date}} | ||
{{/link-to}} | ||
|
||
...becomes... | ||
|
||
<LinkTo @route="post.comment" @models={{array post comment}}> | ||
Comment by {{comment.author.name}} on {{comment.date}} | ||
</LinkTo> | ||
|
||
{{/each}} | ||
{{/let}} | ||
``` | ||
|
||
The singular `@model` argument is a special case of `@models`, provided as a | ||
convenience for the common case. Passing both `@model` and `@models` will be an | ||
error. (So would passing insufficient amount of models for the given route, as | ||
it already is today.) | ||
|
||
It is also possible to pass query params to the `{{link-to}}` component with | ||
the somewhat awkward `(query-params)` API. We propose to replace it with a | ||
`@query` named argument that simply take a regular hash (or POJO): | ||
|
||
```hbs | ||
{{#link-to "posts" (query-params direction="desc" showArchived=false)}} | ||
Recent Posts | ||
{{/link-to}} | ||
|
||
...becomes... | ||
|
||
<LinkTo @route="posts" @query={{hash direction="desc" showArchived=false}}> | ||
Recent Posts | ||
</LinkTo> | ||
``` | ||
|
||
Finally, as mentioned above, `{{link-to}}` supports an "inline" form without a | ||
block. This form doesn't bring much value and used to cause confusion around | ||
the ordering of the arguments. We propose to simply not support this for the | ||
angle bracket invocation style: | ||
|
||
```hbs | ||
{{link-to "About Us" "about"}} | ||
|
||
...becomes... | ||
|
||
<LinkTo @route="about">About Us</LinkTo> | ||
``` | ||
|
||
Other APIs of this compoment are already based on named arguments. | ||
|
||
#### Migration Path | ||
|
||
We would provide a codemod to convert the old invocation style into the new | ||
style. | ||
|
||
#### Deprecations | ||
|
||
Even though the angle bracket invocation style is recommended going forward | ||
(and should be enforced via a template lint), components can generally be | ||
invoked using the either the curly or angle bracket syntax. Therefore, while | ||
not recommended, `{{link-to}}` would still work and invoke the same component. | ||
|
||
In the case that the curly invocation style is used, we propose to issue the | ||
following deprecation warnings: | ||
|
||
* Passing positional arguments to `{{link-to}}` (pass named arguments instead) | ||
* Using the inline form of `{{link-to}}` (use the block form instead) | ||
* The `query-params` helper (pass a hash/POJO to the `query` argument instead) | ||
|
||
### `<Input>` | ||
|
||
Today, the `{{input}}` component is internally implemented as several internal | ||
components that are selected based on the `type` argument. This is intended as | ||
an internal implmentation detail, but as a result, it is not possible to invoke | ||
the component with `<Input>` since it does not exist as a "real" component. | ||
|
||
We propose to change this internal implementation strategy to make it possible | ||
to invoke this with angle brackets just like any other components. | ||
|
||
For example: | ||
|
||
```hbs | ||
{{input type="text" value=this.model.name}} | ||
|
||
...becomes... | ||
|
||
<Input @type="text" @value={{this.model.name}} /> | ||
``` | ||
|
||
Another example: | ||
|
||
```hbs | ||
{{input type="checkbox" name="email-opt-in" checked=this.model.emailPreference}} | ||
|
||
...becomes... | ||
|
||
<Input @type="checkbox" @name="email-opt-in" @checked={{this.model.emailPreference}} /> | ||
``` | ||
|
||
#### Migration Path | ||
|
||
We would provide a codemod to convert the old invocation style into the new | ||
style. | ||
|
||
#### Deprecations | ||
|
||
None. | ||
|
||
### `<TextArea>` | ||
|
||
Due to a similar implementation issue, it is also not possible to invoke the | ||
`{{textarea}}` component with angle bracket invocation style. | ||
|
||
We propose to change this internal implementation strategry to make it possible | ||
mixonic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
to invoke this with angle brackets just like any other components. However, to | ||
align with the name used in [RFC #176](./0176-javascript-module-api.md), we | ||
propose to take this opportunity to rename the component into `<TextArea>` (as | ||
opposed to `<Textarea>`). | ||
|
||
For example: | ||
|
||
```hbs | ||
{{textarea value=this.model.body}} | ||
|
||
...becomes... | ||
|
||
<TextArea @value={{this.model.body}} /> | ||
``` | ||
|
||
#### Migration Path | ||
|
||
We would provide a codemod to convert the old invocation style into the new | ||
style. | ||
|
||
#### Deprecations | ||
|
||
To prevent surprises, `<Textarea>` will also invoke the same component but with | ||
a deprecation warning (use `<TextArea>` instead). | ||
|
||
## How we teach this | ||
|
||
Going forward, we will focus on teaching the angle bracket invocation style as | ||
the main (only?) way of invoking components. In that world, there wouldn't be | ||
anything extra to teach, as the invocation style proposed in this RFC is not | ||
different from any other components, which is the purpose of this proposal. Of | ||
course, the APIs of these components will still need to be taught, but that is | ||
not a new change. | ||
|
||
The only caveat is that, since the advanced `<LinkTo>` APIs require passing | ||
arrays and hashes, the `{{array}}` and `{{hash}}` helper would have to be | ||
taught before those advanced features can be introduced. However, since the | ||
basic usage (linking to top-level routes) does not require either of those | ||
helpers, it doesn't really affect things from a getting started perspective. | ||
|
||
It should also be mentioned that, other built-ins, such as `{{yield}}`, | ||
`{{outlet}}`, `{{mount}}`, etc are considered "keywords" not components, they | ||
are also "control-flow-like", so it wouldn't be appropiate to invoke them with | ||
angle brackets. | ||
|
||
chancancode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
## Drawbacks | ||
|
||
None. | ||
|
||
## Alternatives | ||
|
||
* `<LinkTo>` could only support `@models` without special casing `@model` as a | ||
convenience. | ||
|
||
* `<LinkTo>` could support a `@text` argument for inline usage. | ||
|
||
* `<TextArea>` could just be named `<Textarea>`. | ||
|
||
## Unresolved questions | ||
|
||
None. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we were building these components from first principals, would we choose this API? Might this be an opportunity to build something better, removing
type
and the overloaded input API and instead provide dedicated components such as<TextInput />
and<Checkbox />
? (with possibly better names)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are advantages sticking close to underlying HTML element that it is trying to bridge (even though we don't fully support all the
input
types too). Also, this RFC just tries to fix a narrow problem (provide a 1:1 transition path from the curly invocations) without opening the can of worms of "hey.. what if we also just fix this one thing......", they can be explored in separate RFCs IMO, so long as they are codemod-able I don't think there is a lot of extra cost to do them later.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 thanks, agreed. Having the opportunity to codemod our way to some possible future API means that this is a nice incremental improvement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, but it is not this RFCs intent to "fix the design of the underlying components", that should be done separately.
tldr; what Godfrey said 😸
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same point I came here to make. In particular, given
...attributes
and the semantics oftype
vs.@type
on a regular<input>
, it seems like it might be worth deprecating{{input}}
(along the lines proposed here) and using the internal mechanics which create the correct input type to offer good suggestions. "You attempted to create a checkbox with{{input}}
; we recommend<CheckBox />
..." etc.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think both could work as @rwjblue points out this RFC is to bridge the gap with the commonly used components today. For instance if a Ember dev reads the guide materials on curly vs angle bracket and sees
{{input type="number"}}
being used it's a much smoother path to change it to<Input @type="number">
vs having to know<TextInput type="number" />
or all of the different variations.A more angle bracket 1st set of input components would be great! We could even use codemods or build time AST transforms to rewrite to these new components in the future. But, for now let's make a way to use the built-in components we have.