forked from angular/angular.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtemplate-syntax.jade
1848 lines (1326 loc) · 74.9 KB
/
template-syntax.jade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
block includes
include ../_util-fns
- var _JavaScript = 'JavaScript';
//- Double underscore means don't escape var, use !{__var}.
- var __chaining_op = '<code>;</code> or <code>,</code>';
- var __new_op = '<code>new</code>';
- var __objectAsMap = 'object';
//- The docs standard h4 style uppercases, making code terms unreadable. Override it.
style.
h4 {font-size: 17px !important; text-transform: none !important;}
.syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; }
h4 .syntax { font-size: 100%; }
:marked
The Angular application manages what the user sees and can do, achieving this through the interaction of a
component class instance (the *component*) and its user-facing template.
You may be familiar with the component/template duality from your experience with model-view-controller (MVC) or model-view-viewmodel (MVVM).
In Angular, the component plays the part of the controller/viewmodel, and the template represents the view.
a#toc
:marked
### Table of contents
This guide covers the basic elements of the Angular template syntax, elements you'll need to construct the view:
* [HTML in templates](#html)
* [Interpolation ( <span class="syntax">{{...}}</span> )](#interpolation)
* [Template expressions](#template-expressions)
* [Template statements](#template-statements)
* [Binding syntax](#binding-syntax)
* [Property binding ( <span class="syntax">[property]</span> )](#property-binding)
* [Attribute, class, and style bindings](#other-bindings)
* [Event binding ( <span class="syntax">(event)</span> )](#event-binding)
* [Two-way data binding ( <span class="syntax">[(...)]</span> )](#two-way)
* [Built-in directives](#directives)
* [Built-in attribute directives](#attribute-directives)
* [NgClass](#ngClass)
* [NgStyle](#ngStyle)
* [NgModel (<span class="syntax">[(ngModel)]</span>) ](#ngModel)
* [Built-in structural directives](#structural-directives)
* [NgIf](#ngIf)
* [NgFor](#ngFor)
* [Template input variables](#template-input-variables)
* [Microsyntax](#microsyntax)
* [The NgSwitch directives](#ngSwitch)
* [Template reference variables ( <span class="syntax">#var</span> )](#ref-vars)
* [Input and output properties ( <span class="syntax">@Input</span> and <span class="syntax">@Output</span> )](#inputs-outputs)
* [Template expression operators](#expression-operators)
* [pipe ( <span class="syntax">|</span> )](#pipe)
* [safe navigation operator ( <span class="syntax">?.</span> )](#safe-navigation-operator)
The <live-example></live-example>
demonstrates all of the syntax and code snippets described in this guide.
.l-hr
a#html
:marked
## HTML in templates
HTML is the language of the Angular template.
Almost all HTML syntax is valid template syntax.
The `<script>` element is a notable exception;
it is forbidden, eliminating the risk of script injection attacks.
In practice, `<script>` is ignored and a warning appears in the browser console.
See the [Security](security.html) page for details.
Some legal HTML doesn't make much sense in a template.
The `<html>`, `<body>`, and `<base>` elements have no useful role.
Pretty much everything else is fair game.
You can extend the HTML vocabulary of your templates with components and directives that appear as new elements and attributes.
In the following sections, you'll learn how to get and set DOM (Document Object Model) values dynamically through data binding.
Begin with the first form of data binding—interpolation—to see how much richer template HTML can be.
a(href="#toc") back to top
.l-hr
a#interpolation
:marked
## Interpolation ( <span class="syntax">{{...}}</span> )
You met the double-curly braces of interpolation, `{{` and `}}`, early in your Angular education.
+makeExample('template-syntax/ts/src/app/app.component.html', 'first-interpolation')(format=".")
:marked
You use interpolation to weave calculated strings into the text between HTML element tags and within attribute assignments.
+makeExample('template-syntax/ts/src/app/app.component.html', 'title+image')(format=".")
:marked
The text between the braces is often the name of a component property. Angular replaces that name with the
string value of the corresponding component property. In the example above, Angular evaluates the `title` and `heroImageUrl` properties
and "fills in the blanks", first displaying a bold application title and then a heroic image.
More generally, the text between the braces is a **template expression** that Angular first **evaluates**
and then **converts to a string**. The following interpolation illustrates the point by adding the two numbers:
+makeExample('template-syntax/ts/src/app/app.component.html', 'sum-1')(format=".")
:marked
The expression can invoke methods of the host component such as `getVal()`, seen here:
+makeExample('template-syntax/ts/src/app/app.component.html', 'sum-2')(format=".")
:marked
Angular evaluates all expressions in double curly braces,
converts the expression results to strings, and links them with neighboring literal strings. Finally,
it assigns this composite interpolated result to an **element or directive property**.
You appear to be inserting the result between element tags and assigning it to attributes.
It's convenient to think so, and you rarely suffer for this mistake.
Though this is not exactly true. Interpolation is a special syntax that Angular converts into a
[property binding](#property-binding), as is explained [below](#property-binding-or-interpolation-).
But first, let's take a closer look at template expressions and statements.
a(href="#toc") back to top
.l-hr
a#template-expressions
:marked
## Template expressions
A template **expression** produces a value.
Angular executes the expression and assigns it to a property of a binding target;
the target might be an HTML element, a component, or a directive.
The interpolation braces in `{{1 + 1}}` surround the template expression `1 + 1`.
In the [property binding](#property-binding) section below,
a template expression appears in quotes to the right of the `=` symbol as in `[property]="expression"`.
You write these template expressions in a language that looks like #{_JavaScript}.
Many #{_JavaScript} expressions are legal template expressions, but not all.
#{_JavaScript} expressions that have or promote side effects are prohibited,
including:
* assignments (`=`, `+=`, `-=`, ...)
* !{__new_op}
* chaining expressions with !{__chaining_op}
* increment and decrement operators (`++` and `--`)
:marked
Other notable differences from #{_JavaScript} syntax include:
* no support for the bitwise operators `|` and `&`
* new [template expression operators](#expression-operators), such as `|` and `?.`
a#expression-context
:marked
### Expression context
The *expression context* is typically the _component_ instance.
In the following snippets, the `title` within double-curly braces and the
`isUnchanged` in quotes refer to properties of the `AppComponent`.
+makeExample('template-syntax/ts/src/app/app.component.html', 'context-component-expression')(format=".")
:marked
An expression may also refer to properties of the _template's_ context
such as a [template input variable](#template-input-variable) (`let hero`)
or a [template reference variable](#ref-vars) (`#heroInput`).
+makeExample('template-syntax/ts/src/app/app.component.html', 'context-var')(format=".")
:marked
The context for terms in an expression is a blend of the _template variables_,
the directive's _context_ object (if it has one), and the component's _members_.
If you reference a name that belongs to more than one of these namespaces,
the template variable name takes precedence, followed by a name in the directive's _context_,
and, lastly, the component's member names.
The previous example presents such a name collision. The component has a `hero`
property and the `*ngFor` defines a `hero` template variable.
The `hero` in `{{hero.name}}`
refers to the template input variable, not the component's property.
Template expressions cannot refer to anything in
the global namespace. They can't refer to `window` or `document`. They
can't call `console.log` or `Math.max`. They are restricted to referencing
members of the expression context.
a(href="#toc") back to top
a#no-side-effects
a#expression-guidelines
:marked
### Expression guidelines
Template expressions can make or break an application.
Please follow these guidelines:
* [No visible side effects](#no-visible-side-effects)
* [Quick execution](#quick-execution)
* [Simplicity](#simplicity)
* [Idempotence](#idempotence)
The only exceptions to these guidelines should be in specific circumstances that you thoroughly understand.
#### No visible side effects
A template expression should not change any application state other than the value of the
target property.
This rule is essential to Angular's "unidirectional data flow" policy.
You should never worry that reading a component value might change some other displayed value.
The view should be stable throughout a single rendering pass.
#### Quick execution
Angular executes template expressions after every change detection cycle.
Change detection cycles are triggered by many asynchronous activities such as
promise resolutions, http results, timer events, keypresses and mouse moves.
Expressions should finish quickly or the user experience may drag, especially on slower devices.
Consider caching values when their computation is expensive.
#### Simplicity
Although it's possible to write quite complex template expressions, you should avoid them.
A property name or method call should be the norm.
An occasional Boolean negation (`!`) is OK.
Otherwise, confine application and business logic to the component itself,
where it will be easier to develop and test.
#### Idempotence
An [idempotent](https://en.wikipedia.org/wiki/Idempotence) expression is ideal because
it is free of side effects and improves Angular's change detection performance.
In Angular terms, an idempotent expression always returns *exactly the same thing* until
one of its dependent values changes.
Dependent values should not change during a single turn of the event loop.
If an idempotent expression returns a string or a number, it returns the same string or number
when called twice in a row. If the expression returns an object (including #{_an} `#{_Array}`),
it returns the same object *reference* when called twice in a row.
a(href="#toc") back to top
.l-hr
a#template-statements
:marked
## Template statements
A template **statement** responds to an **event** raised by a binding target
such as an element, component, or directive.
You'll see template statements in the [event binding](#event-binding) section,
appearing in quotes to the right of the `=` symbol as in `(event)="statement"`.
+makeExample('template-syntax/ts/src/app/app.component.html', 'context-component-statement')(format=".")
:marked
A template statement *has a side effect*.
That's the whole point of an event.
It's how you update application state from user action.
Responding to events is the other side of Angular's "unidirectional data flow".
You're free to change anything, anywhere, during this turn of the event loop.
Like template expressions, template *statements* use a language that looks like #{_JavaScript}.
The template statement parser differs from the template expression parser and
specifically supports both basic assignment (`=`) and chaining expressions
(with !{__chaining_op}).
However, certain #{_JavaScript} syntax is not allowed:
* !{__new_op}
* increment and decrement operators, `++` and `--`
* operator assignment, such as `+=` and `-=`
* the bitwise operators `|` and `&`
* the [template expression operators](#expression-operators)
### Statement context
As with expressions, statements can refer only to what's in the statement context
such as an event handling method of the component instance.
The *statement context* is typically the component instance.
The *deleteHero* in `(click)="deleteHero()"` is a method of the data-bound component.
+makeExample('template-syntax/ts/src/app/app.component.html', 'context-component-statement')(format=".")
:marked
The statement context may also refer to properties of the template's own context.
In the following examples, the template `$event` object,
a [template input variable](#template-input-variable) (`let hero`),
and a [template reference variable](#ref-vars) (`#heroForm`)
are passed to an event handling method of the component.
+makeExample('template-syntax/ts/src/app/app.component.html', 'context-var-statement')(format=".")
:marked
Template context names take precedence over component context names.
In `deleteHero(hero)` above, the `hero` is the template input variable,
not the component's `hero` property.
Template statements cannot refer to anything in the global namespace. They
can't refer to `window` or `document`.
They can't call `console.log` or `Math.max`.
### Statement guidelines
As with expressions, avoid writing complex template statements.
A method call or simple property assignment should be the norm.
Now that you have a feel for template expressions and statements,
you're ready to learn about the varieties of data binding syntax beyond interpolation.
a(href="#toc") back to top
.l-hr
a#binding-syntax
:marked
## Binding syntax: An overview
Data binding is a mechanism for coordinating what users see, with application data values.
While you could push values to and pull values from HTML,
the application is easier to write, read, and maintain if you turn these chores over to a binding framework.
You simply declare bindings between binding sources and target HTML elements and let the framework do the work.
Angular provides many kinds of data binding.
This guide covers most of them, after a high-level view of Angular data binding and its syntax.
Binding types can be grouped into three categories distinguished by the direction of data flow:
from the _source-to-view_, from _view-to-source_, and in the two-way sequence: _view-to-source-to-view_:
style td, th {vertical-align: top}
table(width="100%")
col(width="30%")
col(width="50%")
col(width="20%")
tr
th Data direction
th Syntax
th Type
tr
td One-way<br>from data source<br>to view target
td
code-example().
{{expression}}
[target]="expression"
bind-target="expression"
td.
Interpolation<br>
Property<br>
Attribute<br>
Class<br>
Style
tr
td One-way<br>from view target<br>to data source
td
code-example().
(target)="statement"
on-target="statement"
td Event
tr
td Two-way
td
code-example().
[(target)]="expression"
bindon-target="expression"
td Two-way
:marked
Binding types other than interpolation have a **target name** to the left of the equal sign,
either surrounded by punctuation (`[]`, `()`) or preceded by a prefix (`bind-`, `on-`, `bindon-`).
The target name is the name of a _property_. It may look like the name of an _attribute_ but it never is.
To appreciate the difference, you must develop a new way to think about template HTML.
### A new mental model
With all the power of data binding and the ability to extend the HTML vocabulary
with custom markup, it is tempting to think of template HTML as *HTML Plus*.
It really *is* HTML Plus.
But it's also significantly different than the HTML you're used to.
It requires a new mental model.
In the normal course of HTML development, you create a visual structure with HTML elements, and
you modify those elements by setting element attributes with string constants.
+makeExample('template-syntax/ts/src/app/app.component.html', 'img+button')(format=".")
:marked
You still create a structure and initialize attribute values this way in Angular templates.
Then you learn to create new elements with components that encapsulate HTML
and drop them into templates as if they were native HTML elements.
+makeExample('template-syntax/ts/src/app/app.component.html', 'hero-detail-1')(format=".")
:marked
That's HTML Plus.
Then you learn about data binding. The first binding you meet might look like this:
+makeExample('template-syntax/ts/src/app/app.component.html', 'disabled-button-1')(format=".")
:marked
You'll get to that peculiar bracket notation in a moment. Looking beyond it,
your intuition suggests that you're binding to the button's `disabled` attribute and setting
it to the current value of the component's `isUnchanged` property.
Your intuition is incorrect! Your everyday HTML mental model is misleading.
In fact, once you start data binding, you are no longer working with HTML *attributes*. You aren't setting attributes.
You are setting the *properties* of DOM elements, components, and directives.
.l-sub-section
:marked
### HTML attribute vs. DOM property
The distinction between an HTML attribute and a DOM property is crucial to understanding how Angular binding works.
**Attributes are defined by HTML. Properties are defined by the DOM (Document Object Model).**
* A few HTML attributes have 1:1 mapping to properties. `id` is one example.
* Some HTML attributes don't have corresponding properties. `colspan` is one example.
* Some DOM properties don't have corresponding attributes. `textContent` is one example.
* Many HTML attributes appear to map to properties ... but not in the way you might think!
That last category is confusing until you grasp this general rule:
**Attributes *initialize* DOM properties and then they are done.
Property values can change; attribute values can't.**
For example, when the browser renders `<input type="text" value="Bob">`, it creates a
corresponding DOM node with a `value` property *initialized* to "Bob".
When the user enters "Sally" into the input box, the DOM element `value` *property* becomes "Sally".
But the HTML `value` *attribute* remains unchanged as you discover if you ask the input element
about that attribute: `input.getAttribute('value')` returns "Bob".
The HTML attribute `value` specifies the *initial* value; the DOM `value` property is the *current* value.
The `disabled` attribute is another peculiar example. A button's `disabled` *property* is
`false` by default so the button is enabled.
When you add the `disabled` *attribute*, its presence alone initializes the button's `disabled` *property* to `true`
so the button is disabled.
Adding and removing the `disabled` *attribute* disables and enables the button. The value of the *attribute* is irrelevant,
which is why you cannot enable a button by writing `<button disabled="false">Still Disabled</button>`.
Setting the button's `disabled` *property* (say, with an Angular binding) disables or enables the button.
The value of the *property* matters.
**The HTML attribute and the DOM property are not the same thing, even when they have the same name.**
:marked
This fact bears repeating:
**Template binding works with *properties* and *events*, not *attributes*.**
.callout.is-helpful
header A world without attributes
:marked
In the world of Angular, the only role of attributes is to initialize element and directive state.
When you write a data binding, you're dealing exclusively with properties and events of the target object.
HTML attributes effectively disappear.
:marked
With this model firmly in mind, read on to learn about binding targets.
### Binding targets
The **target of a data binding** is something in the DOM.
Depending on the binding type, the target can be an
(element | component | directive) property, an
(element | component | directive) event, or (rarely) an attribute name.
The following table summarizes:
//- If you update this table, UPDATE it in Dart & JS, too.
style td, th {vertical-align: top}
table(width="100%")
col(width="10%")
col(width="15%")
col(width="75%")
tr
th Type
th Target
th Examples
tr
td Property
td.
Element property<br>
Component property<br>
Directive property
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-syntax-1')(format=".")
tr
td Event
td.
Element event<br>
Component event<br>
Directive event
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-syntax-1')(format=".")
tr
td Two-way
td.
Event and property
td
+makeExample('template-syntax/ts/src/app/app.component.html', '2-way-binding-syntax-1')(format=".")
tr
td Attribute
td.
Attribute
(the exception)
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'attribute-binding-syntax-1')(format=".")
tr
td Class
td.
<code>class</code> property
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-syntax-1')(format=".")
tr
td Style
td.
<code>style</code> property
td
+makeExample('template-syntax/ts/src/app/app.component.html', 'style-binding-syntax-1')(format=".")
</div>
:marked
With this broad view in mind, you're ready to look at binding types in detail.
a(href="#toc") back to top
.l-hr
a#property-binding
:marked
## Property binding ( <span class="syntax">[property]</span> )
Write a template **property binding** to set a property of a view element.
The binding sets the property to the value of a [template expression](#template-expressions).
The most common property binding sets an element property to a component property value. An example is
binding the `src` property of an image element to a component's `heroImageUrl` property:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-1')(format=".")
:marked
Another example is disabling a button when the component says that it `isUnchanged`:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-2')(format=".")
:marked
Another is setting a property of a directive:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-3')(format=".")
:marked
Yet another is setting the model property of a custom component (a great way
for parent and child components to communicate):
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-4')(format=".")
:marked
### One-way *in*
People often describe property binding as *one-way data binding* because it flows a value in one direction,
from a component's data property into a target element property.
You cannot use property binding to pull values *out* of the target element.
You can't bind to a property of the target element to _read_ it. You can only _set_ it.
.l-sub-section
:marked
Similarly, you cannot use property binding to *call* a method on the target element.
If the element raises events, you can listen to them with an [event binding](#event-binding).
If you must read a target element property or call one of its methods,
you'll need a different technique.
See the API reference for
[ViewChild](../api/core/index/ViewChild-decorator.html) and
[ContentChild](../api/core/index/ContentChild-decorator.html).
:marked
### Binding target
An element property between enclosing square brackets identifies the target property.
The target property in the following code is the image element's `src` property.
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-1')(format=".")
:marked
Some people prefer the `bind-` prefix alternative, known as the *canonical form*:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-5')(format=".")
:marked
The target name is always the name of a property, even when it appears to be the name of something else.
You see `src` and may think it's the name of an attribute. No. It's the name of an image element property.
Element properties may be the more common targets,
but Angular looks first to see if the name is a property of a known directive,
as it is in the following example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-3')(format=".")
.l-sub-section
:marked
Technically, Angular is matching the name to a directive [input](#inputs-outputs),
one of the property names listed in the directive's `inputs` array or a property decorated with `@Input()`.
Such inputs map to the directive's own properties.
:marked
If the name fails to match a property of a known directive or element, Angular reports an “unknown directive” error.
### Avoid side effects
As mentioned previously, evaluation of a template expression should have no visible side effects.
The expression language itself does its part to keep you safe.
You can't assign a value to anything in a property binding expression nor use the increment and decrement operators.
Of course, the expression might invoke a property or method that has side effects.
Angular has no way of knowing that or stopping you.
The expression could call something like `getFoo()`. Only you know what `getFoo()` does.
If `getFoo()` changes something and you happen to be binding to that something, you risk an unpleasant experience.
Angular may or may not display the changed value. Angular may detect the change and throw a warning error.
In general, stick to data properties and to methods that return values and do no more.
### Return the proper type
The template expression should evaluate to the type of value expected by the target property.
Return a string if the target property expects a string.
Return a number if the target property expects a number.
Return an object if the target property expects an object.
The `hero` property of the `HeroDetail` component expects a `Hero` object, which is exactly what you're sending in the property binding:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-4')(format=".")
:marked
### Remember the brackets
The brackets tell Angular to evaluate the template expression.
If you omit the brackets, Angular treats the string as a constant
and *initializes the target property* with that string.
It does *not* evaluate the string!
Don't make the following mistake:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-6')(format=".")
a#one-time-initialization
:marked
### One-time string initialization
You *should* omit the brackets when all of the following are true:
* The target property accepts a string value.
* The string is a fixed value that you can bake into the template.
* This initial value never changes.
You routinely initialize attributes this way in standard HTML, and it works
just as well for directive and component property initialization.
The following example initializes the `prefix` property of the `HeroDetailComponent` to a fixed string,
not a template expression. Angular sets it and forgets about it.
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-7')(format=".")
:marked
The `[hero]` binding, on the other hand, remains a live binding to the component's `currentHero` property.
### Property binding or interpolation?
You often have a choice between interpolation and property binding.
The following binding pairs do the same thing:
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-vs-interpolation')(format=".")
:marked
_Interpolation_ is a convenient alternative to _property binding_ in many cases.
When rendering data values as strings, there is no technical reason to prefer one form to the other.
You lean toward readability, which tends to favor interpolation.
You suggest establishing coding style rules and choosing the form that
both conforms to the rules and feels most natural for the task at hand.
When setting an element property to a non-string data value, you must use _property binding_.
:marked
#### Content security
Imagine the following *malicious content*.
+makeExample('template-syntax/ts/src/app/app.component.ts', 'evil-title')(format=".")
:marked
Fortunately, Angular data binding is on alert for dangerous HTML.
It *sanitizes* the values before displaying them.
It **will not** allow HTML with script tags to leak into the browser, neither with interpolation
nor property binding.
+makeExample('template-syntax/ts/src/app/app.component.html', 'property-binding-vs-interpolation-sanitization')(format=".")
:marked
Interpolation handles the script tags differently than property binding but both approaches render the
content harmlessly.
figure.image-display
img(src='/resources/images/devguide/template-syntax/evil-title.png' alt="evil title made safe" width='500px')
p
a(href="#toc") back to top
.l-hr
a#other-bindings
:marked
## Attribute, class, and style bindings
The template syntax provides specialized one-way bindings for scenarios less well suited to property binding.
### Attribute binding
You can set the value of an attribute directly with an **attribute binding**.
.l-sub-section
:marked
This is the only exception to the rule that a binding sets a target property.
This is the only binding that creates and sets an attribute.
:marked
This guide stresses repeatedly that setting an element property with a property binding
is always preferred to setting the attribute with a string. Why does Angular offer attribute binding?
**You must use attribute binding when there is no element property to bind.**
Consider the [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA),
[SVG](https://developer.mozilla.org/en-US/docs/Web/SVG), and
table span attributes. They are pure attributes.
They do not correspond to element properties, and they do not set element properties.
There are no property targets to bind to.
This fact becomes painfully obvious when you write something like this.
code-example(language="html").
<tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
:marked
And you get this error:
code-example(format="nocode").
Template parse errors:
Can't bind to 'colspan' since it isn't a known native property
:marked
As the message says, the `<td>` element does not have a `colspan` property.
It has the "colspan" *attribute*, but
interpolation and property binding can set only *properties*, not attributes.
You need attribute bindings to create and bind to such attributes.
Attribute binding syntax resembles property binding.
Instead of an element property between brackets, start with the prefix **`attr`**,
followed by a dot (`.`) and the name of the attribute.
You then set the attribute value, using an expression that resolves to a string.
Bind `[attr.colspan]` to a calculated value:
+makeExample('template-syntax/ts/src/app/app.component.html', 'attrib-binding-colspan')(format=".")
:marked
Here's how the table renders:
<table border="1px">
<tr><td colspan="2">One-Two</td></tr>
<tr><td>Five</td><td>Six</td></tr>
</table>
One of the primary use cases for attribute binding
is to set ARIA attributes, as in this example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'attrib-binding-aria')(format=".")
a(href="#toc") back to top
.l-hr
:marked
### Class binding
You can add and remove CSS class names from an element's `class` attribute with
a **class binding**.
Class binding syntax resembles property binding.
Instead of an element property between brackets, start with the prefix `class`,
optionally followed by a dot (`.`) and the name of a CSS class: `[class.class-name]`.
The following examples show how to add and remove the application's "special" class
with class bindings. Here's how to set the attribute without binding:
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-1')(format=".")
:marked
You can replace that with a binding to a string of the desired class names; this is an all-or-nothing, replacement binding.
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-2')(format=".")
:marked
Finally, you can bind to a specific class name.
Angular adds the class when the template expression evaluates to #{_truthy}.
It removes the class when the expression is #{_falsy}.
+makeExample('template-syntax/ts/src/app/app.component.html', 'class-binding-3')(format=".")
.l-sub-section
:marked
While this is a fine way to toggle a single class name,
the [NgClass directive](#ngClass) is usually preferred when managing multiple class names at the same time.
a(href="#toc") back to top
.l-hr
:marked
### Style binding
You can set inline styles with a **style binding**.
Style binding syntax resembles property binding.
Instead of an element property between brackets, start with the prefix `style`,
followed by a dot (`.`) and the name of a CSS style property: `[style.style-property]`.
+makeExample('template-syntax/ts/src/app/app.component.html', 'style-binding-1')(format=".")
:marked
Some style binding styles have a unit extension.
The following example conditionally sets the font size in “em” and “%” units .
+makeExample('template-syntax/ts/src/app/app.component.html', 'style-binding-2')(format=".")
.l-sub-section
:marked
While this is a fine way to set a single style,
the [NgStyle directive](#ngStyle) is generally preferred when setting several inline styles at the same time.
.l-sub-section
:marked
Note that a _style property_ name can be written in either
[dash-case](glossary.html#dash-case), as shown above, or
[camelCase](glossary.html#camelcase), such as `fontSize`.
a(href="#toc") back to top
.l-hr
a#event-binding
:marked
## Event binding ( <span class="syntax">(event)</span> )
The bindings directives you've met so far flow data in one direction: **from a component to an element**.
Users don't just stare at the screen. They enter text into input boxes. They pick items from lists.
They click buttons. Such user actions may result in a flow of data in the opposite direction:
**from an element to a component**.
The only way to know about a user action is to listen for certain events such as
keystrokes, mouse movements, clicks, and touches.
You declare your interest in user actions through Angular event binding.
Event binding syntax consists of a **target event** name
within parentheses on the left of an equal sign, and a quoted
[template statement](#template-statements) on the right.
The following event binding listens for the button's click events, calling
the component's `onSave()` method whenever a click occurs:
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-1')(format=".")
:marked
### Target event
A **name between parentheses** — for example, `(click)` —
identifies the target event. In the following example, the target is the button's click event.
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-1')(format=".")
:marked
Some people prefer the `on-` prefix alternative, known as the **canonical form**:
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-2')(format=".")
:marked
Element events may be the more common targets, but Angular looks first to see if the name matches an event property
of a known directive, as it does in the following example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-3')(format=".")
.l-sub-section
:marked
The `myClick` directive is further described in the section
on [aliasing input/output properties](#aliasing-io).
:marked
If the name fails to match an element event or an output property of a known directive,
Angular reports an “unknown directive” error.
### *$event* and event handling statements
In an event binding, Angular sets up an event handler for the target event.
When the event is raised, the handler executes the template statement.
The template statement typically involves a receiver, which performs an action
in response to the event, such as storing a value from the HTML control
into a model.
The binding conveys information about the event, including data values, through
an **event object named `$event`**.
The shape of the event object is determined by the target event.
If the target event is a native DOM element event, then `$event` is a
[DOM event object]( https://developer.mozilla.org/en-US/docs/Web/Events),
with properties such as `target` and `target.value`.
Consider this example:
+makeExample('template-syntax/ts/src/app/app.component.html', 'without-NgModel')(format=".")
:marked
This code sets the input box `value` property by binding to the `name` property.
To listen for changes to the value, the code binds to the input box's `input` event.
When the user makes changes, the `input` event is raised, and the binding executes
the statement within a context that includes the DOM event object, `$event`.
To update the `name` property, the changed text is retrieved by following the path `$event.target.value`.
If the event belongs to a directive (recall that components are directives),
`$event` has whatever shape the directive decides to produce.
a#eventemitter
a#custom-event
:marked
### Custom events with <span class="syntax">EventEmitter</span>
Directives typically raise custom events with an Angular [EventEmitter](../api/core/index/EventEmitter-class.html).
The directive creates an `EventEmitter` and exposes it as a property.
The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload, which can be anything.
Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object.
Consider a `HeroDetailComponent` that presents hero information and responds to user actions.
Although the `HeroDetailComponent` has a delete button it doesn't know how to delete the hero itself.
The best it can do is raise an event reporting the user's delete request.
Here are the pertinent excerpts from that `HeroDetailComponent`:
+makeExcerpt('src/app/hero-detail.component.ts (template)', 'template-1')
+makeExcerpt('src/app/hero-detail.component.ts', 'deleteRequest')
:marked
The component defines a `deleteRequest` property that returns an `EventEmitter`.
When the user clicks *delete*, the component invokes the `delete()` method,
telling the `EventEmitter` to emit a `Hero` object.
Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s `deleteRequest` event.
+makeExcerpt('src/app/app.component.html', 'event-binding-to-component', '')
:marked
When the `deleteRequest` event fires, Angular calls the parent component's `deleteHero` method,
passing the *hero-to-delete* (emitted by `HeroDetail`) in the `$event` variable.
### Template statements have side effects
The `deleteHero` method has a side effect: it deletes a hero.
Template statement side effects are not just OK, but expected.
Deleting the hero updates the model, perhaps triggering other changes
including queries and saves to a remote server.
These changes percolate through the system and are ultimately displayed in this and other views.
//-
:marked
### Event bubbling and propagation [TODO: reinstate this section when it becomes true]
Angular invokes the event-handling statement if the event is raised by the current element or one of its child elements.
+makeExample('template-syntax/ts/src/app/app.component.html', 'event-binding-bubbling')(format=".")
:marked
Many DOM events, both [native](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Overview_of_Events_and_Handlers ) and [custom](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events ), bubble up their ancestor tree of DOM elements until an event handler along the way prevents further propagation.
.l-sub-section
:marked
`EventEmitter` events don't bubble.
:marked
The result of an event binding statement determines whether
[event propagation](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples#Example_5:_Event_Propagation)
continues or stops with the current element.
Event propagation stops if the binding statement returns a falsy value (as does a method with no return value).
Clicking the button in the next example triggers a save;
the click doesn't make it to the outer `<div>` so the div's save handler is not called.