-
-
Notifications
You must be signed in to change notification settings - Fork 497
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
Review and Octanify the template guides #598
Conversation
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.
@mixonic a few thoughts / comments, but thanks, that's much appreciated!
} | ||
} | ||
``` | ||
|
||
## Modifying the action's first parameter |
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.
Did you remove this section because it ended up seeming confusing?
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.
@acorncom excellent question! While editing these guide entries I was surprised to see onclick={{action this.foo}}
-style actions being used widely. I brought it up vaguely in #st-octane
and once my thoughts were more organized in #core-framework
on Discord.
In Glimmer components there is no actions hash. Even with the @action
decorator the following doesn't work:
import Component from '@glimmer/component';
import { action } from '@ember/object';
export default class extends Component {
@action
doThing() {
// Do it!
}
}
<button {{action 'doThing'}}>Do it!</button>
You cannot use a string to reference the action on the actions hash because there is no actions hash. And on glimmer component we see no need to create one. Note that a similar issue exists for native-class-Ember-component's which use the @action
decorator and for native-class-syntax-controllers which do the same. They don't have an actions hash to reference with the string.
Instead, we intend to suggest developers reach for the @action
-decorated property/method itself. For example:
import Component from '@glimmer/component';
import { action } from '@ember/object';
export default class extends Component {
@action
doThing() {
// Do it!
}
}
<button {{action this.doThing}}>Do it!</button>
But wait, I can just use onclick
!
Clever developers will note that the above is using the action helper where it isn't strictly going to be needed. They might reach for the following:
{{!
I know that @action binds the method to the component, so I'll just use
use the bare method/action.
}}
<button onclick={{this.doThing}}>Do it!</button>
We would like to make this fail a linter check. Teaching that developers write an action this way has several downsides:
onclick=
teaches that you can always attach an event listener withonfoo=
syntax. This is not actually true. Some DOM elements trigger events (such asfocusin
) without calling the related property. Additionally web components don't call these properties. Instead you must attach an event listener. If developers learn this API first they will start off on the wrong foot.onclick=
works because Ember today has a "prop first, fallback to attribute" rule for how to set attributes on an element. Props can have subtle differences between attributes, even for the same values. More significantly properties have no way to be serialized into HTML, making them very difficult and in some cases impossible to pass to the browser when doing server-side rendering.onclick=
provides the developer no opportunity to pass arguments to the event listener. For examplepassive: true
orcapture: true
. We should provide developers an API where opting into options for their listener is straightforward.- Finally we already have an API in
<button {{action this.doThing}}>
that does the work ofonclick=
. There are definitely ways to improve on the action modifier and helper, butonclick=
doesn't offer much.
But it does offer me one thing: The event!
Correct! Using onclick=
done one thing that the modifier {{action
does not: It gives you access to the event. For example this calls the action alert
with the value of the input every time it changes:
<input onchange={{action this.alert value="target.value"}}>
And this exact use of the API is what this subsection of the guide page is talking about. Although this behavior is not deprecated (and may be useful) we will not be suggesting onfoo=
elsewhere for all the reasons outlined above, and so I do not think we should introduce this uncommon usage in the guides. It remains documented in the API docs
But I really don't like <button {{action this.foo}}>
Right. I agree it isn't all we want. For example you still can't add a listener for a custom event emitted by a web component to the action modifier. You can pass some useful arguments but not passive: true
. You cannot get access to the event object.
Additionally some of the more advanced developers might know that the action modifier and helper have a special property: They bind an action passed to them to the context
(or the value of the target=
option if you pass one). They might think: "Ah ha you don't need the @action
decorator!". But we do. We need the @action
decorator to bind the actions onto the component so that in the future we can move from the action modifier (and maybe helper) to something better. We will provide a check that fails if you try to use {{action this.someProp}}
and someProp
has not had the @action
decorator applied.
There is strong support among framework core that something akin to https://github.com/buschtoens/ember-on-modifier could become a built-in for Ember. The on
modifier would solve most of the pain points around {{action
. We cannot be sure it would ship in Octane at this late date, but we should consider soon how we can migrate existing action usage over to that new and better tool.
Final legacy note
Ember components and controllers with classic .extend({
should continue to use the action modifier or helper with the string argument. That class definition syntax does not have the ability to use the action decorator, and we see no need to churn code using that API with anything new.
* call them arguments (not parameters) * use `positional` and `named`
Re: #588
/cc @pzuraq @jenweber