@@ -397,16 +397,17 @@ The only difference is that now we've componentized our list into a version that
397
397
You can see this in action if you create a new route that shows a different list of people.
398
398
As an additional exercise (that we won't cover),
399
399
you can try to create a ` programmers ` route that shows a list of famous programmers.
400
- 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.
401
401
402
402
## Responding to user interactions
403
403
404
404
So far, our application is listing data, but there is no way for the user to
405
405
interact with the information. In web applications we often want to respond to
406
406
user actions like clicks or hovers. Ember makes this easy to do.
407
407
408
- First, we can modify the ` < PeopleList> ` component to include a button:
408
+ First, we can modify the ` PeopleList ` component to include a button:
409
409
410
+ <feature-flag-off-template-tag >
410
411
``` handlebars {data-filename="app/components/people-list.hbs"}
411
412
<h2>{{@title}}</h2>
412
413
@@ -418,16 +419,34 @@ First, we can modify the `<PeopleList>` component to include a button:
418
419
{{/each}}
419
420
</ul>
420
421
```
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
+
421
439
422
440
Now that we have a button, we need to wire it up to do _ something_ when a user
423
441
clicks on it. For simplicity, let's say we want to show an ` alert ` dialog with
424
442
the person's name when the button is clicked.
425
443
426
- So far, our ` < PeopleList> ` component is purely presentational – it takes some
444
+ So far, our ` PeopleList ` component is purely presentational – it takes some
427
445
inputs as arguments and renders them using a template. To introduce _ behavior_
428
446
to our component – handling the button click in this case, we will need to
429
- attach some _ code _ to the component.
447
+ attach some JavaScript to the component.
430
448
449
+ <feature-flag-off-template-tag >
431
450
In addition to the template, a component can also have a JavaScript file for
432
451
this exact purpose. Go ahead and create a ` .js ` file with the same name and in
433
452
the same directory as our template (` app/components/people-list.js ` ),
@@ -496,6 +515,95 @@ helper to pass the `person` as an argument which our action expects.
496
515
497
516
Feel free to try this in the browser. Finally, everything should behave exactly
498
517
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
+
499
607
500
608
## Building For Production
501
609
0 commit comments