Skip to content

Commit 8fcae19

Browse files
authored
Merge pull request #2091 from ember-learn/template-tag-quick-start
Converting more quick-start page content to use template tag
2 parents b974634 + a679ce0 commit 8fcae19

File tree

1 file changed

+216
-7
lines changed

1 file changed

+216
-7
lines changed

guides/release/getting-started/quick-start.md

+216-7
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ ember generate route scientists
135135

136136
You'll see output like this:
137137

138+
<feature-flag-off-template-tag>
138139
```text
139140
installing route
140141
create app/routes/scientists.js
@@ -144,6 +145,20 @@ updating router
144145
installing route-test
145146
create tests/unit/routes/scientists-test.js
146147
```
148+
</feature-flag-off-template-tag>
149+
<feature-flag-on-template-tag>
150+
```bash
151+
# 🚧 Under construction 🚧
152+
# `ember generate route` has not been updated to produce GJS files yet.
153+
installing route
154+
create app/routes/scientists.js
155+
create app/templates/scientists.gjs
156+
updating router
157+
add route scientists
158+
installing route-test
159+
create tests/unit/routes/scientists-test.js
160+
```
161+
</feature-flag-on-template-tag>
147162

148163
That is Ember telling you that it has created:
149164

@@ -152,6 +167,7 @@ That is Ember telling you that it has created:
152167
3. An entry in the application's router (located in `app/router.js`).
153168
4. A unit test for this route.
154169

170+
<feature-flag-off-template-tag>
155171
Open the newly-created template in `app/templates/scientists.hbs` and add the following HTML:
156172

157173
```handlebars {data-filename=app/templates/scientists.hbs}
@@ -162,6 +178,24 @@ Open the newly-created template in `app/templates/scientists.hbs` and add the fo
162178
In your browser, open [`http://localhost:4200/scientists`](http://localhost:4200/scientists).
163179
You should see the `<h2>` we put in the `scientists.hbs` template right below the `<h1>` from our `application.hbs` template.
164180

181+
</feature-flag-off-template-tag>
182+
<feature-flag-on-template-tag>
183+
Open the newly-created template in `app/templates/scientists.gjs` and add the following HTML:
184+
185+
```gjs {data-filename=app/templates/scientists.gjs}
186+
import { pageTitle } from 'ember-page-title';
187+
188+
<template>
189+
{{pageTitle "Scientists"}}
190+
<h2>List of Scientists</h2>
191+
</template>
192+
```
193+
194+
In your browser, open [`http://localhost:4200/scientists`](http://localhost:4200/scientists).
195+
You should see the `<h2>` we put in the `scientists.gjs` template right below the `<h1>` from our `application.gjs` template.
196+
197+
</feature-flag-on-template-tag>
198+
165199
Since the scientist route is nested under the application route, Ember will render its content inside the application route template's `{{outlet}}` directive.
166200

167201
Now that we've got the `scientists` template rendering,
@@ -191,6 +225,7 @@ the `model()` method supports any library that uses [JavaScript Promises](https:
191225
Now let's tell Ember how to turn that array of strings into HTML.
192226
Open the `scientists` template and add the following code to loop through the array and print it:
193227

228+
<feature-flag-off-template-tag>
194229
```handlebars {data-filename="app/templates/scientists.hbs"}
195230
<h2>List of Scientists</h2>
196231
@@ -200,6 +235,23 @@ Open the `scientists` template and add the following code to loop through the ar
200235
{{/each}}
201236
</ul>
202237
```
238+
</feature-flag-off-template-tag>
239+
240+
<feature-flag-on-template-tag>
241+
```gjs {data-filename="app/templates/scientists.gjs"}
242+
import { pageTitle } from 'ember-page-title';
243+
244+
<template>
245+
{{pageTitle "Scientists"}}
246+
<h2>List of Scientists</h2>
247+
<ul>
248+
{{#each @model as |scientist|}}
249+
<li>{{scientist}}</li>
250+
{{/each}}
251+
</ul>
252+
</template>
253+
```
254+
</feature-flag-on-template-tag>
203255

204256
Here, we use the `each` _helper_ to loop over each item in the array we
205257
provided from the `model()` hook. Ember will render the _block_ contained
@@ -217,16 +269,21 @@ As your application grows, you will notice you are sharing UI elements between m
217269
or using them multiple times on the same page.
218270
Ember makes it easy to refactor your templates into reusable components.
219271

220-
Let's create a `<PeopleList>` component that we can use in multiple places to show a list of people.
272+
Let's create a `PeopleList` component that we can use in multiple places to show a list of people.
221273

222274
As usual, there's a generator that makes this easy for us.
223275
Make a new component by typing:
224276

225277
```bash
278+
<feature-flag-on-template-tag>
279+
# 🚧 Under construction 🚧
280+
# `ember generate component` has not been updated to produce GJS files yet.
281+
</feature-flag-on-template-tag>
226282
ember generate component people-list
227283
```
228284

229-
Copy and paste the `scientists` template into the `<PeopleList>` component's template and edit it to look as follows:
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:
230287

231288
```handlebars {data-filename=app/components/people-list.hbs}
232289
<h2>{{@title}}</h2>
@@ -238,6 +295,25 @@ Copy and paste the `scientists` template into the `<PeopleList>` component's tem
238295
</ul>
239296
```
240297

298+
</feature-flag-off-template-tag>
299+
300+
<feature-flag-on-template-tag>
301+
Copy and paste this part of the `scientists` template into the `PeopleList` component and edit it to look as follows:
302+
303+
```gjs {data-filename=app/components/people-list.gjs}
304+
<template>
305+
<h2>{{@title}}</h2>
306+
307+
<ul>
308+
{{#each @people as |person|}}
309+
<li>{{person}}</li>
310+
{{/each}}
311+
</ul>
312+
</template>
313+
```
314+
315+
</feature-flag-on-template-tag>
316+
241317
Note that we've changed the title from a hard-coded string ("List of Scientists")
242318
to `{{@title}}`. The `@` indicates that `@title` is an argument that will be
243319
passed into the component, which makes it easier to reuse the same component in
@@ -246,7 +322,8 @@ other parts of the app we are building.
246322
We've also renamed `scientist` to the more-generic `person`,
247323
decreasing the coupling of our component to where it's used.
248324

249-
Our component is called `<PeopleList>`, based on its name on the file system. Please note that the letters P and L are capitalized.
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.
250327

251328
<div class="cta">
252329
<div class="cta-note">
@@ -261,6 +338,7 @@ Our component is called `<PeopleList>`, based on its name on the file system. Pl
261338
<img src="/images/mascots/zoey.png" role="presentation" alt="">
262339
</div>
263340
</div>
341+
</feature-flag-off-template-tag>
264342

265343
Save this template and switch back to the `scientists` template.
266344

@@ -276,6 +354,7 @@ In the rest of the code examples in this tutorial, whenever we add or remove cod
276354

277355
Let's replace all our old code with our new componentized version:
278356

357+
<feature-flag-off-template-tag>
279358
```handlebars {data-filename="app/templates/scientists.hbs" data-diff="-1,-2,-3,-4,-5,-6,-7,+8,+9,+10,+11"}
280359
<h2>List of Scientists</h2>
281360
@@ -289,23 +368,46 @@ Let's replace all our old code with our new componentized version:
289368
@people={{@model}}
290369
/>
291370
```
371+
</feature-flag-off-template-tag>
372+
373+
<feature-flag-on-template-tag>
374+
```gjs {data-filename="app/templates/scientists.gjs" data-diff="+2,-6,-7,-8,-9,-10,-11,+12,+13,+14,+15"}
375+
import { pageTitle } from 'ember-page-title';
376+
import PeopleList from '../components/people-list';
377+
378+
<template>
379+
{{pageTitle "Scientists"}}
380+
<h2>List of Scientists</h2>
381+
<ul>
382+
{{#each @model as |scientist|}}
383+
<li>{{scientist}}</li>
384+
{{/each}}
385+
</ul>
386+
<PeopleList
387+
@title="List of Scientists"
388+
@people={{@model}}
389+
/>
390+
</template>
391+
```
392+
</feature-flag-on-template-tag>
292393

293394
Go back to your browser and you should see that the UI looks identical.
294395
The only difference is that now we've componentized our list into a version that's more reusable and more maintainable.
295396

296397
You can see this in action if you create a new route that shows a different list of people.
297398
As an additional exercise (that we won't cover),
298399
you can try to create a `programmers` route that shows a list of famous programmers.
299-
If you re-use the `<PeopleList>` component, you can do it with almost no code at all.
400+
If you re-use the `PeopleList` component, you can do it with almost no code at all.
300401

301402
## Responding to user interactions
302403

303404
So far, our application is listing data, but there is no way for the user to
304405
interact with the information. In web applications we often want to respond to
305406
user actions like clicks or hovers. Ember makes this easy to do.
306407

307-
First, we can modify the `<PeopleList>` component to include a button:
408+
First, we can modify the `PeopleList` component to include a button:
308409

410+
<feature-flag-off-template-tag>
309411
```handlebars {data-filename="app/components/people-list.hbs"}
310412
<h2>{{@title}}</h2>
311413
@@ -317,16 +419,34 @@ First, we can modify the `<PeopleList>` component to include a button:
317419
{{/each}}
318420
</ul>
319421
```
422+
</feature-flag-off-template-tag>
423+
<feature-flag-on-template-tag>
424+
```gjs {data-filename="app/components/people-list.gjs"}
425+
<template>
426+
<h2>{{@title}}</h2>
427+
428+
<ul>
429+
{{#each @people as |person|}}
430+
<li>
431+
<button type="button">{{person}}</button>
432+
</li>
433+
{{/each}}
434+
</ul>
435+
</template>
436+
```
437+
</feature-flag-on-template-tag>
438+
320439

321440
Now that we have a button, we need to wire it up to do _something_ when a user
322441
clicks on it. For simplicity, let's say we want to show an `alert` dialog with
323442
the person's name when the button is clicked.
324443

325-
So far, our `<PeopleList>` component is purely presentational – it takes some
444+
So far, our `PeopleList` component is purely presentational – it takes some
326445
inputs as arguments and renders them using a template. To introduce _behavior_
327446
to our component – handling the button click in this case, we will need to
328-
attach some _code_ to the component.
447+
attach some JavaScript to the component.
329448

449+
<feature-flag-off-template-tag>
330450
In addition to the template, a component can also have a JavaScript file for
331451
this exact purpose. Go ahead and create a `.js` file with the same name and in
332452
the same directory as our template (`app/components/people-list.js`),
@@ -395,6 +515,95 @@ helper to pass the `person` as an argument which our action expects.
395515

396516
Feel free to try this in the browser. Finally, everything should behave exactly
397517
as we hoped!
518+
</feature-flag-off-template-tag>
519+
520+
<feature-flag-on-template-tag>
521+
522+
Let's use the [`on` modifier](../../components/template-lifecycle-dom-and-modifiers/#toc_event-handlers) to handle click events on the button:
523+
524+
```gjs {data-filename="app/components/people-list.gjs"}
525+
import { on } from '@ember/modifier'
526+
527+
function showPerson(clickEvent) {
528+
alert(`You clicked on a button labeled ${clickEvent.target.innerHTML}`);
529+
}
530+
531+
<template>
532+
<h2>{{@title}}</h2>
533+
534+
<ul>
535+
{{#each @people as |person|}}
536+
<li>
537+
<button type="button" {{on "click" showPerson}}>{{person}}</button>
538+
</li>
539+
{{/each}}
540+
</ul>
541+
</template>
542+
```
543+
544+
Now let's extend our example to pass the Person to our event handler as an argument. We can use the [`fn` helper](../../components/component-state-and-actions/#toc_passing-arguments-to-actions):
545+
546+
```gjs {data-filename="app/components/people-list.gjs"}
547+
import { on } from '@ember/modifier'
548+
import { fn } from '@ember/helper';
549+
550+
function showPerson(person) {
551+
alert(`You clicked on ${person}`);
552+
}
553+
554+
<template>
555+
<h2>{{@title}}</h2>
556+
557+
<ul>
558+
{{#each @people as |person|}}
559+
<li>
560+
<button type="button" {{on "click" (fn showPerson person) }}>{{person}}</button>
561+
</li>
562+
{{/each}}
563+
</ul>
564+
</template>
565+
```
566+
567+
Many components will need to maintain some state. Let's introduce a `currentPerson` that keeps track of which Person the user clicked on last. The idiomatic way to keep state in an Ember component is to use [`@tracked`](../../in-depth-topics/autotracking-in-depth/) on a component class:
568+
569+
```gjs {data-filename="app/components/people-list.gjs"}
570+
import { on } from '@ember/modifier'
571+
import { fn } from '@ember/helper';
572+
import { tracked } from '@glimmer/tracking';
573+
import Component from '@glimmer/component';
574+
575+
export default class extends Component {
576+
@tracked currentPerson;
577+
578+
showPerson = (person) => {
579+
this.currentPerson = person;
580+
};
581+
582+
isCurrentPerson = (person) => {
583+
return this.currentPerson === person;
584+
};
585+
586+
<template>
587+
<h2>{{@title}}</h2>
588+
589+
<ul>
590+
{{#each @people as |person|}}
591+
<li>
592+
<button type="button" {{on "click" (fn this.showPerson person) }}>{{person}}</button>
593+
{{#if (this.isCurrentPerson person) }}
594+
⬅️
595+
{{/if}}
596+
</li>
597+
{{/each}}
598+
</ul>
599+
</template>
600+
}
601+
```
602+
603+
</feature-flag-on-template-tag>
604+
605+
606+
398607

399608
## Building For Production
400609

0 commit comments

Comments
 (0)