Skip to content

Commit 976ef34

Browse files
authored
Merge pull request ember-learn#574 from ember-learn/feat/octane/templates
[OCTANE][FEAT] Templates
2 parents 272f442 + 4af956a commit 976ef34

File tree

6 files changed

+245
-219
lines changed

6 files changed

+245
-219
lines changed

guides/release/pages.yml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
pages:
2020
- title: "Templating Basics"
2121
url: "handlebars-basics"
22-
- title: "Built-in Helpers"
23-
url: "built-in-helpers"
2422
- title: "Conditionals"
2523
url: "conditionals"
2624
- title: "Displaying a List of Items"
@@ -29,15 +27,10 @@
2927
url: "displaying-the-keys-in-an-object"
3028
- title: "Binding Element Attributes"
3129
url: "binding-element-attributes"
32-
- title: "Links"
33-
url: "links"
3430
- title: "Actions"
3531
url: "actions"
36-
- title: "Input Helpers"
37-
url: "input-helpers"
38-
- title: "Development Helpers"
39-
url: "development-helpers"
40-
isAdvanced: true
32+
- title: "Built-in Helpers"
33+
url: "built-in-helpers"
4134
- title: "Writing Helpers"
4235
url: "writing-helpers"
4336
isAdvanced: true

guides/release/templates/actions.md

Lines changed: 106 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,126 @@
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+
```
420

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>
929
10-
```handlebars {data-filename=app/templates/components/single-post.hbs}
11-
<h3><button {{action "toggleBody"}}>{{this.title}}</button></h3>
1230
{{#if this.isShowingBody}}
1331
<p>{{this.body}}</p>
1432
{{/if}}
1533
```
1634

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:
1938

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';
2242

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');
2849
}
29-
});
50+
}
3051
```
3152

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.
3456

3557
## Action Parameters
3658

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
6560
[`{{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:
6862

69-
You can specify an alternative event by using the `on` option.
70-
71-
```handlebars
63+
```handlebars {data-filename=app/components/post/template.hbs}
7264
<p>
73-
<button {{action "select" this.post on="mouseUp"}}>✓</button>
65+
<button onclick={{action this.select this.post}}>
66+
67+
</button>
7468
{{this.post.title}}
7569
</p>
7670
```
7771

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:
8074

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';
8279

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;
8682

87-
```handlebars
88-
<button {{action "anActionName" allowedKeys="alt"}}>
89-
click me
90-
</button>
83+
@action
84+
select(post) {
85+
this.selectedPost = post;
86+
}
87+
}
9188
```
9289

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:
9792

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';
10197

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;
105100

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+
}
108108
```
109109

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-
116110
## Modifying the action's first parameter
117111

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.
123116

124117
```handlebars
125118
<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+
/>
127124
```
128125

129126
Let's assume we have an action handler that prints its first parameter:
@@ -137,38 +134,42 @@ actions: {
137134
```
138135

139136
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 {}`.
142139

143140
Using the `value` option modifies that behavior by extracting that property from
144141
the event object:
145142

146143
```handlebars
147144
<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+
/>
149150
```
150151

151152
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')
153155

154156
## Attaching Actions to Non-Clickable Elements
155157

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:
162163

163164
```css
164165
[data-ember-action]:not(:disabled) {
165166
cursor: pointer;
166167
}
167168
```
168169

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

Comments
 (0)