1
- Your app will often need a way to let users interact with controls that
2
- change application state. For example, imagine that you have a template
3
- that shows a blog title, and supports expanding the post to show the body.
1
+ Your app will often need a way to let users interact with controls that change
2
+ application state. For example, imagine that you have a template that shows a
3
+ blog title, and supports expanding the post to show the body. This can be done
4
+ with _ actions_ .
5
+
6
+ Actions are methods that have been decorated with the ` @action ` decorator in
7
+ the context of the template:
8
+
9
+ ``` javascript {data-filename=app/components/post/component.js}
10
+ import Component from ' @glimmer/component' ;
11
+ import { action } from ' @ember/object' ;
12
+
13
+ export default class Post extends Component {
14
+ @action
15
+ toggleBody () {
16
+ this .toggleProperty (' isShowingBody' );
17
+ }
18
+ }
19
+ ```
4
20
5
- If you add the
6
- [ ` {{action}} ` ] ( https://www.emberjs.com/api/ember/release/classes/Ember.Templates.helpers/methods/action?anchor=action )
7
- helper to any HTML DOM element, when a user clicks the element, the named event
8
- will be sent to the template's corresponding component or controller.
21
+ You can then add this action directly to an [ _ event handler
22
+ property_ ] ( https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers )
23
+ on an element, like ` onclick ` or ` onmouseenter ` :
24
+
25
+ ``` handlebars {data-filename=app/components/post/template.hbs}
26
+ <h3>
27
+ <button onclick={{this.toggleBody}}>{{this.title}}</button>
28
+ </h3>
9
29
10
- ``` handlebars {data-filename=app/templates/components/single-post.hbs}
11
- <h3><button {{action "toggleBody"}}>{{this.title}}</button></h3>
12
30
{{#if this.isShowingBody}}
13
31
<p>{{this.body}}</p>
14
32
{{/if}}
15
33
```
16
34
17
- In the component or controller, you can then define what the action does within
18
- the ` actions ` hook:
35
+ This assigns the action to the standard browser event handler for that function.
36
+ It'll receive the event as its first parameter, and you can handle it like any
37
+ standard JavaScript event:
19
38
20
- ``` javascript {data-filename=app/components/single-post.js}
21
- import Component from ' @ember/component' ;
39
+ ``` javascript {data-filename=app/components/post/component.js}
40
+ import Component from ' @glimmer/component' ;
41
+ import { action } from ' @ember/object' ;
22
42
23
- export default Component .extend ({
24
- actions: {
25
- toggleBody () {
26
- this .toggleProperty (' isShowingBody' );
27
- }
43
+ export default class Post extends Component {
44
+ @action
45
+ toggleBody (event ) {
46
+ event .preventDefault ();
47
+ event .stopPropagation ();
48
+ this .toggleProperty (' isShowingBody' );
28
49
}
29
- });
50
+ }
30
51
```
31
52
32
- You will learn about more advanced usages in the Component's [ Triggering Changes With Actions] ( ../../components/triggering-changes-with-actions/ ) guide,
33
- but you should familiarize yourself with the following basics first.
53
+ You will learn about more advanced usages in the Component's [ Actions and
54
+ Events] ( ../../components/actions-and-events/ ) guide, but you should familiarize
55
+ yourself with the following basics first.
34
56
35
57
## Action Parameters
36
58
37
- You can optionally pass arguments to the action handler. Any values
38
- passed to the ` {{action}} ` helper after the action name will be passed to
39
- the handler as arguments.
40
-
41
- For example, if the ` post ` argument was passed:
42
-
43
- ``` handlebars
44
- <p><button {{action "select" this.post}}>✓</button> {{this.post.title}}</p>
45
- ```
46
-
47
- The ` select ` action handler would be called with a single argument
48
- containing the post model:
49
-
50
- ``` javascript {data-filename=app/components/single-post.js}
51
- import Component from ' @ember/component' ;
52
-
53
- export default Component .extend ({
54
- actions: {
55
- select (post ) {
56
- console .log (post .get (' title' ));
57
- }
58
- }
59
- });
60
- ```
61
-
62
- ## Specifying the Type of Event
63
-
64
- By default, the
59
+ You can optionally pass arguments to the action with the
65
60
[ ` {{action}} ` ] ( https://www.emberjs.com/api/ember/release/classes/Ember.Templates.helpers/methods/action?anchor=action )
66
- helper listens for click events and triggers the action when the user clicks
67
- on the element.
61
+ helper. For example, if the ` post ` argument was passed:
68
62
69
- You can specify an alternative event by using the ` on ` option.
70
-
71
- ``` handlebars
63
+ ``` handlebars {data-filename=app/components/post/template.hbs}
72
64
<p>
73
- <button {{action "select" this.post on="mouseUp"}}>✓</button>
65
+ <button onclick={{action this.select this.post}}>
66
+ ✓
67
+ </button>
74
68
{{this.post.title}}
75
69
</p>
76
70
```
77
71
78
- You should use the < code >camelCased</ code > event names, so two-word names like ` keypress `
79
- become ` keyPress ` .
72
+ The ` select ` action handler would be called with a single argument
73
+ containing the post model:
80
74
81
- ## Allowing Modifier Keys
75
+ ``` javascript {data-filename=app/components/post/component.js}
76
+ import Component from ' @glimmer/component' ;
77
+ import { tracked } from ' @glimmer/tracking' ;
78
+ import { action } from ' @ember/object' ;
82
79
83
- By default, the ` {{action}} ` helper will ignore click events with
84
- pressed modifier keys. You can supply an ` allowedKeys ` option
85
- to specify which keys should not be ignored.
80
+ export default class Post extends Component {
81
+ @tracked selectedPost;
86
82
87
- ``` handlebars
88
- <button {{action "anActionName" allowedKeys="alt"}}>
89
- click me
90
- </button>
83
+ @action
84
+ select (post ) {
85
+ this .selectedPost = post;
86
+ }
87
+ }
91
88
```
92
89
93
- This way the ` {{action}} ` will fire when clicking with the alt key
94
- pressed down.
95
-
96
- ## Allowing Default Browser Action
90
+ If you pass arguments like this, the event will be the _ last_ argument that is
91
+ passed to the handler:
97
92
98
- By default, the ` {{action}} ` helper prevents the default browser action of the
99
- DOM event. If you want to allow the browser action, you can stop Ember from
100
- preventing it.
93
+ ``` javascript {data-filename=app/components/post/component.js}
94
+ import Component from ' @glimmer/component' ;
95
+ import { tracked } from ' @glimmer/tracking' ;
96
+ import { action } from ' @ember/object' ;
101
97
102
- For example, if you have a normal link tag and want the link to bring the user
103
- to another page in addition to triggering an ember action when clicked, you can
104
- use ` preventDefault=false ` :
98
+ export default class Post extends Component {
99
+ @tracked selectedPost;
105
100
106
- ``` handlebars
107
- <a href="newPage.htm" {{action "logClick" preventDefault=false}}>Go</a>
101
+ @action
102
+ select (post , event ) {
103
+ event .preventDefault ();
104
+ event .stopPropagation ();
105
+ this .selectedPost = post;
106
+ }
107
+ }
108
108
```
109
109
110
- With ` preventDefault=false ` omitted, if the user clicked on the link, Ember.js
111
- will trigger the action, but the user will remain on the current page.
112
-
113
- With ` preventDefault=false ` present, if the user clicked on the link, Ember.js
114
- will trigger the action * and* the user will be directed to the new page.
115
-
116
110
## Modifying the action's first parameter
117
111
118
- If a ` value ` option for the
119
- [ ` {{action}} ` ] ( https://www.emberjs.com/api/ember/release/classes/Ember.Templates.helpers/methods/action?anchor=action )
120
- helper is specified, its value will be considered a property path that will
121
- be read off of the first parameter of the action. This comes very handy with
122
- event listeners and enables to work with one-way bindings.
112
+ If a ` value ` option for the ` {{action}} ` helper is specified, its value will be
113
+ considered a property path that will be read off of the first parameter of the
114
+ action. This comes very handy with event listeners and enables to work with
115
+ one-way bindings.
123
116
124
117
``` handlebars
125
118
<label>What's your favorite band?</label>
126
- <input type="text" value={{this.favoriteBand}} onblur={{action "bandDidChange"}} />
119
+ <input
120
+ type="text"
121
+ value={{this.favoriteBand}}
122
+ onblur={{this.bandDidChange}}
123
+ />
127
124
```
128
125
129
126
Let's assume we have an action handler that prints its first parameter:
@@ -137,38 +134,42 @@ actions: {
137
134
```
138
135
139
136
By default, the action handler receives the first parameter of the event
140
- listener, the event object the browser passes to the handler, so
141
- ` bandDidChange ` prints ` Event {} ` .
137
+ listener, the event object the browser passes to the handler, so ` bandDidChange `
138
+ prints ` Event {} ` .
142
139
143
140
Using the ` value ` option modifies that behavior by extracting that property from
144
141
the event object:
145
142
146
143
``` handlebars
147
144
<label>What's your favorite band?</label>
148
- <input type="text" value={{this.favoriteBand}} onblur={{action "bandDidChange" value="target.value"}} />
145
+ <input
146
+ type="text"
147
+ value={{this.favoriteBand}}
148
+ onblur={{action this.bandDidChange value="target.value"}}
149
+ />
149
150
```
150
151
151
152
The ` newValue ` parameter thus becomes the ` target.value ` property of the event
152
- object, which is the value of the input field the user typed. (e.g 'Foo Fighters')
153
+ object, which is the value of the input field the user typed. (e.g 'Foo
154
+ Fighters')
153
155
154
156
## Attaching Actions to Non-Clickable Elements
155
157
156
- Note that actions may be attached to any element of the DOM, but not all
157
- respond to the ` click ` event. For example, if an action is attached to an ` a `
158
- link without an ` href ` attribute, or to a ` div ` , some browsers won't execute
159
- the associated function. If it's really needed to define actions over such
160
- elements, a CSS workaround exists to make them clickable, ` cursor: pointer ` .
161
- For example:
158
+ Note that actions may be attached to any element of the DOM, but not all respond
159
+ to the ` click ` event. For example, if an action is attached to an ` a ` link
160
+ without an ` href ` attribute, or to a ` div ` , some browsers won't execute the
161
+ associated function. If it's really needed to define actions over such elements,
162
+ a CSS workaround exists to make them clickable, ` cursor: pointer ` . For example:
162
163
163
164
``` css
164
165
[data-ember-action ]:not (:disabled ) {
165
166
cursor : pointer ;
166
167
}
167
168
```
168
169
169
- Keep in mind that even with this workaround in place, the ` click ` event will
170
- not automatically trigger via keyboard driven ` click ` equivalents (such as
171
- the ` enter ` key when focused). Browsers will trigger this on clickable
172
- elements only by default. This also doesn't make an element accessible to
173
- users of assistive technology. You will need to add additional things like
174
- ` role ` and/or ` tabindex ` to make this accessible for your users.
170
+ Keep in mind that even with this workaround in place, the ` click ` event will not
171
+ automatically trigger via keyboard driven ` click ` equivalents (such as the
172
+ ` enter ` key when focused). Browsers will trigger this on clickable elements only
173
+ by default. This also doesn't make an element accessible to users of assistive
174
+ technology. You will need to add additional things like ` role ` and/or ` tabindex `
175
+ to make this accessible for your users.
0 commit comments