Deprecate (action)
template helper and {{action}}
modifier.
Summary
The (action)
template helper and {{action}}
modifier was common pre-Octane. Now that we have native classes and the {{on}}
modifier, we no longer need to use (action)
or {{action}}
Motivation
Remove legacy code with confusing semantics.
This is a part of Deprecating Ember Classic (pre-Octane).
Transition Path
This was written in the Octave vs Classic cheatsheet
that content here
Before (pre-Octane)
// parent-component.js
import Component from '@ember/component';
export default Component.extend({
count: 0
});
{{!-- parent-component.hbs --}}
{{child-component count=count}}
Count: {{this.count}}
// child-component.js
import Component from '@ember/component';
export default Component.extend({
actions: {
plusOne() {
this.set('count', this.get('count') + 1);
}
}
});
{{!-- child-component.hbs --}}
<button type="button" {{action "plusOne"}}>
Click Me
</button>
After (post-Octane)
// parent-component.js
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
export default class ParentComponent extends Component {
@tracked count = 0;
@action plusOne() {
this.count++;
}
}
{{!-- parent-component.hbs --}}
<ChildComponent @plusOne={{this.plusOne}} />
Count: {{this.count}}
{{!-- child-component.hbs --}}
<button type="button" {{on "click" @plusOne}}>
Click Me
</button>
But what we could put in the deprecation app:
Scenario: action
is passed a string
Before:
<button type="button" {{action "plusOne"}}>
Click Me
</button>
After
<button type="button" {{on 'click' this.plusOne}}>
Click Me
</button>
or, if plusOne
is passed in as an argument
<button type="button" {{on 'click' @plusOne}}>
Click Me
</button>
If the plusOne
action is in an actions object, it needs to move out:
Before:
import Component from '@glimmer/component';
export default class Demo extends Component {
actions = {
plusOne() {
/* ... */
}
}
}
or
import Component from '@ember/component';
export default class Demo extends Component {
actions = {
plusOne() {
/* ... */
}
}
}
or
import Component from '@ember/component';
export default Component.extend({
actions: {
plusOne() {
/* ... */
}
}
})
After:
import Component from '@glimmer/component';
import { action } from '@ember/object';
export default class Demo extends Component {
@action
plusOne() {
/* ... */
}
}
Note that @action
is completely different from (action)
or {{action}}
(and is partly a motivator for deprecating (action)
and {{action}}
, to reduce ambiguity).
@action
is binds the this
on the method to the instance of the class.
Scenario: action
is passed a function reference
Before:
<SomeComponent @update={{action this.plusOne}} />
After
<SomeComponent @update={{this.plusOne}} />
Scenario: action
is passed parameters
Before:
<SomeComponent @update={{action this.plus 1}} />
After:
<SomeComponent @update={{fn this.plus 1}} />
Scenario: action
is used with mut
Before:
<SomeComponent @update={{action (mut @value.property)}} />
After:
// parent.js
import Component from '@glimmer/component';
import { action } from '@ember/object';
export default class SomeComponent extends Component {
@action
handleUpdate(value) {
this.args.property = value;
}
}
{{! parent.hbs }}
<SomeComponent @update={{this.handleUpdate}} />
Related, Combining function arguments with action functions
Related: send
When removing (action)
or {{action}}
with a string name, you'll also need to verify that there are no send
calls with that same string.
How We Teach This
The guides already cover how to invoke functions in the modern way.
Remove: https://api.emberjs.com/ember/5.6/classes/Ember.Templates.helpers/methods/action?anchor=action
Drawbacks
Older code will stop working once the deprecated code is removed.
Alternatives
- adding an import so folks can keep using action in gjs. I don't think we should do this because we want to clean up antiquated patterns, rather than encourage their continued existence.
Unresolved questions
- Could there be a codemod?
Potentially for action usage that references
this.properties
. For string actions, it's impossible.