@@ -87,8 +87,6 @@ Congratulations! You just created and booted your first Ember app.
87
87
88
88
## Write some HTML in a template
89
89
90
- <feature-flag-on-template-tag >
91
-
92
90
We will start by editing the ` application ` template.
93
91
This template is always on screen while the user has your application loaded.
94
92
In your editor, open ` app/templates/application.gjs ` and change it to the following:
@@ -99,21 +97,6 @@ In your editor, open `app/templates/application.gjs` and change it to the follow
99
97
{{outlet}}
100
98
</template>
101
99
```
102
- </feature-flag-on-template-tag >
103
-
104
- <feature-flag-off-template-tag >
105
-
106
- We will start by editing the ` application ` template.
107
- This template is always on screen while the user has your application loaded.
108
- In your editor, open ` app/templates/application.hbs ` and change it to the following:
109
-
110
- ``` handlebars {data-filename=app/templates/application.hbs}
111
- <h1>PeopleTracker</h1>
112
-
113
- {{outlet}}
114
- ```
115
-
116
- </feature-flag-off-template-tag >
117
100
118
101
Ember detects the changed file and automatically reloads the page for you in the background.
119
102
You should see that the welcome page has been replaced by "PeopleTracker".
@@ -135,18 +118,6 @@ ember generate route scientists
135
118
136
119
You'll see output like this:
137
120
138
- <feature-flag-off-template-tag >
139
- ``` text
140
- installing route
141
- create app/routes/scientists.js
142
- create app/templates/scientists.hbs
143
- updating router
144
- add route scientists
145
- installing route-test
146
- create tests/unit/routes/scientists-test.js
147
- ```
148
- </feature-flag-off-template-tag >
149
- <feature-flag-on-template-tag >
150
121
``` bash
151
122
# 🚧 Under construction 🚧
152
123
# `ember generate route` has not been updated to produce GJS files yet.
@@ -158,7 +129,6 @@ updating router
158
129
installing route-test
159
130
create tests/unit/routes/scientists-test.js
160
131
```
161
- </feature-flag-on-template-tag >
162
132
163
133
That is Ember telling you that it has created:
164
134
@@ -167,19 +137,6 @@ That is Ember telling you that it has created:
167
137
3 . An entry in the application's router (located in ` app/router.js ` ).
168
138
4 . A unit test for this route.
169
139
170
- <feature-flag-off-template-tag >
171
- Open the newly-created template in ` app/templates/scientists.hbs ` and add the following HTML:
172
-
173
- ``` handlebars {data-filename=app/templates/scientists.hbs}
174
- {{page-title "Scientists"}}
175
- <h2>List of Scientists</h2>
176
- ```
177
-
178
- In your browser, open [ ` http://localhost:4200/scientists ` ] ( http://localhost:4200/scientists ) .
179
- You should see the ` <h2> ` we put in the ` scientists.hbs ` template right below the ` <h1> ` from our ` application.hbs ` template.
180
-
181
- </feature-flag-off-template-tag >
182
- <feature-flag-on-template-tag >
183
140
Open the newly-created template in ` app/templates/scientists.gjs ` and add the following HTML:
184
141
185
142
``` gjs {data-filename=app/templates/scientists.gjs}
@@ -194,8 +151,6 @@ import { pageTitle } from 'ember-page-title';
194
151
In your browser, open [ ` http://localhost:4200/scientists ` ] ( http://localhost:4200/scientists ) .
195
152
You should see the ` <h2> ` we put in the ` scientists.gjs ` template right below the ` <h1> ` from our ` application.gjs ` template.
196
153
197
- </feature-flag-on-template-tag >
198
-
199
154
Since the scientist route is nested under the application route, Ember will render its content inside the application route template's ` {{outlet}} ` directive.
200
155
201
156
Now that we've got the ` scientists ` template rendering,
@@ -225,19 +180,6 @@ the `model()` method supports any library that uses [JavaScript Promises](https:
225
180
Now let's tell Ember how to turn that array of strings into HTML.
226
181
Open the ` scientists ` template and add the following code to loop through the array and print it:
227
182
228
- <feature-flag-off-template-tag >
229
- ``` handlebars {data-filename="app/templates/scientists.hbs"}
230
- <h2>List of Scientists</h2>
231
-
232
- <ul>
233
- {{#each @model as |scientist|}}
234
- <li>{{scientist}}</li>
235
- {{/each}}
236
- </ul>
237
- ```
238
- </feature-flag-off-template-tag >
239
-
240
- <feature-flag-on-template-tag >
241
183
``` gjs {data-filename="app/templates/scientists.gjs"}
242
184
import { pageTitle } from 'ember-page-title';
243
185
@@ -251,7 +193,6 @@ import { pageTitle } from 'ember-page-title';
251
193
</ul>
252
194
</template>
253
195
```
254
- </feature-flag-on-template-tag >
255
196
256
197
Here, we use the ` each ` _ helper_ to loop over each item in the array we
257
198
provided from the ` model() ` hook. Ember will render the _ block_ contained
@@ -275,29 +216,10 @@ As usual, there's a generator that makes this easy for us.
275
216
Make a new component by typing:
276
217
277
218
``` bash
278
- < feature-flag-on-template-tag>
279
219
# 🚧 Under construction 🚧
280
220
# `ember generate component` has not been updated to produce GJS files yet.
281
- < /feature-flag-on-template-tag>
282
- ember generate component people-list
283
- ```
284
-
285
- <feature-flag-off-template-tag >
286
- Copy and paste the ` scientists ` template into the ` PeopleList ` component's template and edit it to look as follows:
287
-
288
- ``` handlebars {data-filename=app/components/people-list.hbs}
289
- <h2>{{@title}}</h2>
290
-
291
- <ul>
292
- {{#each @people as |person|}}
293
- <li>{{person}}</li>
294
- {{/each}}
295
- </ul>
296
221
```
297
222
298
- </feature-flag-off-template-tag >
299
-
300
- <feature-flag-on-template-tag >
301
223
Copy and paste this part of the ` scientists ` template into the ` PeopleList ` component and edit it to look as follows:
302
224
303
225
``` gjs {data-filename=app/components/people-list.gjs}
@@ -312,8 +234,6 @@ Copy and paste this part of the `scientists` template into the `PeopleList` comp
312
234
</template>
313
235
```
314
236
315
- </feature-flag-on-template-tag >
316
-
317
237
Note that we've changed the title from a hard-coded string ("List of Scientists")
318
238
to ` {{@title}} ` . The ` @ ` indicates that ` @title ` is an argument that will be
319
239
passed into the component, which makes it easier to reuse the same component in
@@ -322,24 +242,6 @@ other parts of the app we are building.
322
242
We've also renamed ` scientist ` to the more-generic ` person ` ,
323
243
decreasing the coupling of our component to where it's used.
324
244
325
- <feature-flag-off-template-tag >
326
- Our component is called ` PeopleList ` , based on its name on the file system. Please note that the letters P and L are capitalized.
327
-
328
- <div class =" cta " >
329
- <div class =" cta-note " >
330
- <div class="cta-note-body">
331
- <div class="cta-note-heading">Zoey says...</div>
332
- <div class="cta-note-message">
333
- A component's name is derived from its file name.
334
- We capitalize the first letter and every letter after <code>-</code>, then remove the hyphens.
335
- This is known as pascal case.
336
- </div>
337
- </div>
338
- <img src="/images/mascots/zoey.png" role="presentation" alt="">
339
- </div >
340
- </div >
341
- </feature-flag-off-template-tag >
342
-
343
245
Save this template and switch back to the ` scientists ` template.
344
246
345
247
We're going to tell our component:
@@ -354,23 +256,6 @@ In the rest of the code examples in this tutorial, whenever we add or remove cod
354
256
355
257
Let's replace all our old code with our new componentized version:
356
258
357
- <feature-flag-off-template-tag >
358
- ``` handlebars {data-filename="app/templates/scientists.hbs" data-diff="-1,-2,-3,-4,-5,-6,-7,+8,+9,+10,+11"}
359
- <h2>List of Scientists</h2>
360
-
361
- <ul>
362
- {{#each @model as |scientist|}}
363
- <li>{{scientist}}</li>
364
- {{/each}}
365
- </ul>
366
- <PeopleList
367
- @title="List of Scientists"
368
- @people={{@model}}
369
- />
370
- ```
371
- </feature-flag-off-template-tag >
372
-
373
- <feature-flag-on-template-tag >
374
259
``` gjs {data-filename="app/templates/scientists.gjs" data-diff="+2,-6,-7,-8,-9,-10,-11,+12,+13,+14,+15"}
375
260
import { pageTitle } from 'ember-page-title';
376
261
import PeopleList from '../components/people-list';
@@ -389,7 +274,6 @@ import PeopleList from '../components/people-list';
389
274
/>
390
275
</template>
391
276
```
392
- </feature-flag-on-template-tag >
393
277
394
278
Go back to your browser and you should see that the UI looks identical.
395
279
The only difference is that now we've componentized our list into a version that's more reusable and more maintainable.
@@ -407,20 +291,6 @@ user actions like clicks or hovers. Ember makes this easy to do.
407
291
408
292
First, we can modify the ` PeopleList ` component to include a button:
409
293
410
- <feature-flag-off-template-tag >
411
- ``` handlebars {data-filename="app/components/people-list.hbs"}
412
- <h2>{{@title}}</h2>
413
-
414
- <ul>
415
- {{#each @people as |person|}}
416
- <li>
417
- <button type="button">{{person}}</button>
418
- </li>
419
- {{/each}}
420
- </ul>
421
- ```
422
- </feature-flag-off-template-tag >
423
- <feature-flag-on-template-tag >
424
294
``` gjs {data-filename="app/components/people-list.gjs"}
425
295
<template>
426
296
<h2>{{@title}}</h2>
@@ -434,8 +304,6 @@ First, we can modify the `PeopleList` component to include a button:
434
304
</ul>
435
305
</template>
436
306
```
437
- </feature-flag-on-template-tag >
438
-
439
307
440
308
Now that we have a button, we need to wire it up to do _ something_ when a user
441
309
clicks on it. For simplicity, let's say we want to show an ` alert ` dialog with
@@ -446,79 +314,6 @@ inputs as arguments and renders them using a template. To introduce _behavior_
446
314
to our component – handling the button click in this case, we will need to
447
315
attach some JavaScript to the component.
448
316
449
- <feature-flag-off-template-tag >
450
- In addition to the template, a component can also have a JavaScript file for
451
- this exact purpose. Go ahead and create a ` .js ` file with the same name and in
452
- the same directory as our template (` app/components/people-list.js ` ),
453
- and paste in the following content:
454
-
455
- ``` javascript {data-filename="app/components/people-list.js"}
456
- import Component from ' @glimmer/component' ;
457
- import { action } from ' @ember/object' ;
458
-
459
- export default class PeopleListComponent extends Component {
460
- @action
461
- showPerson (person ) {
462
- alert (` The person's name is ${ person} !` );
463
- }
464
- }
465
- ```
466
-
467
- _ Note: If you want this file created for you, you may pass the ` -gc ` flag when running the component generator._
468
-
469
- Here, we created a basic component class and added a method that accepts a
470
- person as an argument and brings up an alert dialog with their name. The
471
- ` @action ` _ decorator_ indicates we want to use this method as an _ action_
472
- in our template, in response to user interaction.
473
-
474
- Now that we have implemented the desired behavior, we can go back to
475
- the component's template and wire everything up:
476
-
477
- ``` handlebars {data-filename="app/components/people-list.hbs" data-diff="-6,+7"}
478
- <h2>{{@title}}</h2>
479
-
480
- <ul>
481
- {{#each @people as |person|}}
482
- <li>
483
- <button type="button">{{person}}</button>
484
- <button type="button" {{on 'click' this.showPerson}}>{{person}}</button>
485
- </li>
486
- {{/each}}
487
- </ul>
488
- ```
489
-
490
- Here, we used the ` on ` _ modifier_ to attach the ` this.showPerson ` action to
491
- the button in the template.
492
-
493
- There is a problem with this though – if you tried this in the browser, you
494
- will quickly discover that clicking on the buttons will bring up an alert
495
- dialog that said "The person's name is ` [Object MouseEvent] ` !" – eek!
496
-
497
- The cause of this bug is that we wrote our action to take an argument – the
498
- person's name – and we forgot to pass it. The fix is easy enough:
499
-
500
- ``` handlebars {data-filename="app/components/people-list.hbs" data-diff="-6,+7"}
501
- <h2>{{@title}}</h2>
502
-
503
- <ul>
504
- {{#each @people as |person|}}
505
- <li>
506
- <button type="button" {{on 'click' this.showPerson}}>{{person}}</button>
507
- <button type="button" {{on 'click' (fn this.showPerson person)}}>{{person}}</button>
508
- </li>
509
- {{/each}}
510
- </ul>
511
- ```
512
-
513
- Instead of passing the action to the ` on ` modifier directly, we used the ` fn `
514
- helper to pass the ` person ` as an argument which our action expects.
515
-
516
- Feel free to try this in the browser. Finally, everything should behave exactly
517
- as we hoped!
518
- </feature-flag-off-template-tag >
519
-
520
- <feature-flag-on-template-tag >
521
-
522
317
Let's use the [ ` on ` modifier] ( ../../components/template-lifecycle-dom-and-modifiers/#toc_event-handlers ) to handle click events on the button:
523
318
524
319
``` gjs {data-filename="app/components/people-list.gjs"}
@@ -600,11 +395,6 @@ export default class extends Component {
600
395
}
601
396
```
602
397
603
- </feature-flag-on-template-tag >
604
-
605
-
606
-
607
-
608
398
## Building For Production
609
399
610
400
Now that we've written our application and verified that it works in development,
0 commit comments