@@ -21,6 +21,7 @@ block includes
21
21
* [Property binding](#property-binding)
22
22
* [Attribute, class, and style bindings](#other-bindings)
23
23
* [Event binding](#event-binding)
24
+ * [Two-way data binding](#two-way)
24
25
* [Two-way data binding with `NgModel`](#ngModel)
25
26
* [Built-in directives](#directives)
26
27
* [NgClass](#ngClass)
@@ -44,7 +45,7 @@ block includes
44
45
HTML is the language of the Angular template. Our [QuickStart](../quickstart.html) application has a template that is pure HTML:
45
46
46
47
code-example( language ="html" escape ="html" ) .
47
- <h1 >My First Angular 2 App</h1 >
48
+ <h1 >My First Angular App</h1 >
48
49
49
50
:marked
50
51
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 simply ignored.)
@@ -387,7 +388,7 @@ table
387
388
.callout.is-helpful
388
389
header A world without attributes
389
390
:marked
390
- In the world of Angular 2 , the only role of attributes is to initialize element and directive state.
391
+ In the world of Angular, the only role of attributes is to initialize element and directive state.
391
392
When we data bind, we're dealing exclusively with element and directive properties and events.
392
393
Attributes effectively disappear.
393
394
:marked
@@ -489,8 +490,8 @@ table
489
490
If we must read a target element property or call one of its methods,
490
491
we'll need a different technique.
491
492
See the API reference for
492
- [viewChild](../api/core/index/ViewChild-var .html) and
493
- [contentChild](../api/core/index/ContentChild-var .html).
493
+ [viewChild](../api/core/index/ViewChild-decorator .html) and
494
+ [contentChild](../api/core/index/ContentChild-decorator .html).
494
495
495
496
:marked
496
497
### Binding target
@@ -711,12 +712,12 @@ block style-property-name-dart-diff
711
712
712
713
.l-main-section
713
714
:marked
714
- ## Event Binding
715
- The bindings we’ve met so far flow data in one direction: *from the component to an element*.
715
+ ## Event binding
716
+ The bindings we’ve met so far flow data in one direction: ** from a component to an element* *.
716
717
717
718
Users don’t just stare at the screen. They enter text into input boxes. They pick items from lists.
718
719
They click buttons. Such user actions may result in a flow of data in the opposite direction:
719
- *from an element to the component*.
720
+ ** from an element to a component* *.
720
721
721
722
The only way to know about a user action is to listen for certain events such as
722
723
keystrokes, mouse movements, clicks, and touches.
@@ -728,12 +729,12 @@ block style-property-name-dart-diff
728
729
the component's `onSave()` method whenever a click occurs:
729
730
+ makeExample('template-syntax/ts/app/app.component.html' , 'event-binding-1' )( format ="." )
730
731
:marked
731
- ### Target Event
732
- A **name between enclosing parentheses** — for example, `(click)` —
732
+ ### Target event
733
+ A **name between parentheses** — for example, `(click)` —
733
734
identifies the target event. In the following example, the target is the button’s click event.
734
735
+ makeExample('template-syntax/ts/app/app.component.html' , 'event-binding-1' )( format ="." )
735
736
:marked
736
- Some people prefer the `on-` prefix alternative, known as the *canonical form*:
737
+ Some people prefer the `on-` prefix alternative, known as the ** canonical form* *:
737
738
+ makeExample('template-syntax/ts/app/app.component.html' , 'event-binding-2' )( format ="." )
738
739
:marked
739
740
Element events may be the more common targets, but Angular looks first to see if the name matches an event property
@@ -742,47 +743,46 @@ block style-property-name-dart-diff
742
743
743
744
.l-sub-section
744
745
:marked
745
- The `myClick` directive is further described below in the section
746
- on [Aliasing input/output properties](#aliasing-io).
746
+ The `myClick` directive is further described in the section
747
+ on [aliasing input/output properties](#aliasing-io).
747
748
748
749
:marked
749
- If the name fails to match an element event or an output property of a known directive,
750
+ If the name fails to match element event or output property of a known directive,
750
751
Angular reports an “unknown directive” error.
751
752
752
753
### *$event* and event handling statements
753
754
In an event binding, Angular sets up an event handler for the target event.
754
755
755
756
When the event is raised, the handler executes the template statement.
756
- The template statement typically involves a receiver that wants to do something
757
- in response to the event, such as take a value from the HTML control and store it
758
- in a model.
757
+ The template statement typically involves a receiver, which performs an action
758
+ in response to the event, such as storing a value from the HTML control
759
+ into a model.
759
760
760
761
The binding conveys information about the event, including data values, through
761
762
an **event object named `$event`**.
762
763
763
- The shape of the event object is determined by the target event itself .
764
- If the target event is a native DOM element event, the `$event` is a
764
+ The shape of the event object is determined by the target event.
765
+ If the target event is a native DOM element event, then `$event` is a
765
766
[DOM event object]( https://developer.mozilla.org/en-US/docs/Web/Events),
766
767
with properties such as `target` and `target.value`.
767
768
768
769
Consider this example:
769
770
+ makeExample('template-syntax/ts/app/app.component.html' , 'without-NgModel' )( format ="." )
770
771
:marked
771
- We’re binding the input box `value` to a `firstName` property, and we’re listening for changes by binding to the input box’ s `input` event.
772
+ This code sets the input box `value` property by binding to the `firstName` property. To listen for changes to the value, the code binds to the input box' s `input` event.
772
773
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`.
773
774
774
- To update the `firstName` property, we must get the changed text by following
775
- the path `$event.target.value`.
775
+ To update the `firstName` property, the changed text is retrieved by following the path `$event.target.value`.
776
776
777
- If the event belongs to a directive (remember: components are directives), `$event` has whatever shape the directive chose to produce.
777
+ If the event belongs to a directive (recall that components are directives), `$event` has whatever shape the directive decides to produce.
778
778
779
779
<a id="eventemitter"></a>
780
780
<a id="custom-event"></a>
781
781
### Custom Events with EventEmitter
782
782
783
783
Directives typically raise custom events with an Angular [EventEmitter](../api/core/index/EventEmitter-class.html).
784
- A directive creates an `EventEmitter` and exposes it as a property.
785
- The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload that can be anything.
784
+ The directive creates an `EventEmitter` and exposes it as a property.
785
+ The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload, which can be anything.
786
786
Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object.
787
787
788
788
Consider a `HeroDetailComponent` that presents hero information and responds to user actions.
@@ -797,8 +797,8 @@ block style-property-name-dart-diff
797
797
798
798
:marked
799
799
The component defines a `deleteRequest` property that returns an `EventEmitter`.
800
- When the user clicks *delete*, the component invokes the `delete()` method
801
- which tells the `EventEmitter` to emit a `Hero` object.
800
+ When the user clicks *delete*, the component invokes the `delete()` method,
801
+ telling the `EventEmitter` to emit a `Hero` object.
802
802
803
803
Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s `deleteRequest` event.
804
804
@@ -810,12 +810,11 @@ block style-property-name-dart-diff
810
810
811
811
### Template statements have side effects
812
812
The `deleteHero` method has a side effect: it deletes a hero.
813
- Template statement side effects are not just OK, they are expected.
813
+ Template statement side effects are not just OK, but expected.
814
814
815
815
Deleting the hero updates the model, perhaps triggering other changes
816
816
including queries and saves to a remote server.
817
817
These changes percolate through the system and are ultimately displayed in this and other views.
818
- It's all good.
819
818
820
819
//
821
820
:marked
@@ -843,19 +842,64 @@ block style-property-name-dart-diff
843
842
and the outer `<div>`, causing a double save.
844
843
+makeExample('template-syntax/ts/app/app.component.html', 'event-binding-propagation')(format=".")
845
844
845
+ #two-way
846
+ .l-main-section
847
+ :marked
848
+ ## Two-way binding
849
+ We often want to both display a data property and update that property when the user makes changes.
850
+
851
+ On the element side that takes a combination of setting a specific element property
852
+ and listening for an element change event.
853
+
854
+ Angular offers a special _two-way data binding_ syntax for this purpose, **`[(x)]`**.
855
+ The `[(x)]` syntax combines the brackets
856
+ of _Property Binding_, `[x]`, with the parentheses of _Event Binding_, `(x)`.
857
+ .callout.is-important
858
+ header [( )] = banana in a box
859
+ :marked
860
+ Visualize a *banana in a box* to remember that the parentheses go _inside_ the brackets.
861
+ :marked
862
+ The `[(x)]` syntax is easy to demonstrate when the element has a settable property called `x`
863
+ and a corresponding event named `xChange`.
864
+ Here's a `SizerComponent` that fits the pattern.
865
+ It has a `size` value property and a companion `sizeChange` event:
866
+ + makeExample('template-syntax/ts/app/sizer.component.ts' , null , 'app/sizer.component.ts' )
867
+ :marked
868
+ The initial `size` is an input value from a property binding.
869
+ Clicking the buttons increases or decreases the `size`, within min/max values constraints,
870
+ and then raises (_emits_) the `sizeChange` event with the adjusted size.
846
871
872
+ Here's an example in which the `AppComponent.fontSize` is two-way bound to the `SizerComponent`:
873
+ + makeExample('template-syntax/ts/app/app.component.html' , 'two-way-1' )( format ="." )
874
+ :marked
875
+ The `AppComponent.fontSize` establishes the initial `SizerComponent.size` value.
876
+ Clicking the buttons updates the `AppComponent.fontSize` via the two-way binding.
877
+ The revised `AppComponent.fontSize` value flows through to the _style_ binding, making the displayed text bigger or smaller.
878
+ Try it in the <live-example>live example</live-example>.
879
+
880
+ The two-way binding syntax is really just syntactic sugar for a _property_ binding and an _event_ binding.
881
+ Angular _desugars_ the `SizerComponent` binding into this:
882
+ + makeExample('template-syntax/ts/app/app.component.html' , 'two-way-2' )( format ="." )
883
+ :marked
884
+ The `$event` variable contains the payload of the `SizerComponent.sizeChange` event.
885
+ Angular assigns the `$event` value to the `AppComponent.fontSize` when the user clicks the buttons.
886
+
887
+ Clearly the two-way binding syntax is a great convenience compared to separate property and event bindings.
888
+
889
+ We'd like to use two-way binding with HTML form elements like `<input>` and `<select>`.
890
+ Sadly, no native HTML element follows the `x` value and `xChange` event pattern.
891
+
892
+ Fortunately, the Angular [_NgModel_](#ngModel) directive is a bridge that enables two-way binding to form elements.
893
+
894
+ a#ngModel
847
895
.l-main-section
848
896
:marked
849
- <a id="ngModel"></a>
850
897
## Two-way binding with NgModel
851
898
When developing data entry forms, we often want to both display a data property and update that property when the user makes changes.
852
899
853
- The `[(ngModel)]` two -way data binding syntax makes that easy. Here's an example:
900
+ Two -way data binding with the `NgModel` directive makes that easy. Here's an example:
854
901
+ makeExample('template-syntax/ts/app/app.component.html' , 'NgModel-1' )( format ="." )
855
- .callout.is-important
856
- header [()] = banana in a box
857
- :marked
858
- To remember that the parentheses go inside the brackets, visualize a *banana in a box*.
902
+
859
903
860
904
+ ifDocsFor('ts|js' )
861
905
.callout.is-important
@@ -865,54 +909,48 @@ block style-property-name-dart-diff
865
909
we must import the `FormsModule` and add it to the Angular module's `imports` list.
866
910
Learn more about the `FormsModule` and `ngModel` in the
867
911
[Forms](../guide/forms.html#ngModel) chapter.
868
-
912
+ :marked
913
+ Here's how to import the `FormsModule` to make `[(ngModel)]` available.
869
914
+ makeExample('template-syntax/ts/app/app.module.1.ts' , '' , 'app.module.ts (FormsModule import)' )
870
915
871
916
:marked
872
- There’s a story behind this construction, a story that builds on the property and event binding techniques we learned previously.
873
-
874
917
### Inside `[(ngModel)]`
875
- We could have achieved the same result with separate bindings to
918
+ Looking back at the `firstName` binding, it's important to note that
919
+ we could have achieved the same result with separate bindings to
876
920
the `<input>` element's `value` property and `input` event.
877
921
+ makeExample('template-syntax/ts/app/app.component.html' , 'without-NgModel' )( format ="." )
878
922
:marked
879
- That’s cumbersome. Who can remember which element property to set and what event reports user changes?
923
+ That’s cumbersome. Who can remember which element property to set and which element event emits user changes?
880
924
How do we extract the currently displayed text from the input box so we can update the data property?
881
925
Who wants to look that up each time?
882
926
883
927
That `ngModel` directive hides these onerous details behind its own `ngModel` input and `ngModelChange` output properties.
884
928
+ makeExample('template-syntax/ts/app/app.component.html' , 'NgModel-3' )( format ="." )
885
929
.l-sub-section
886
930
:marked
887
- The `ngModel` input property sets the element's value property and the `ngModelChange` output property
931
+ The `ngModel` data property sets the element's value property and the `ngModelChange` event property
888
932
listens for changes to the element's value.
889
- The details are specific to each kind of element and therefore the `NgModel` directive only works for elements,
890
- such as the input text box, that are supported by a [ControlValueAccessor](../api/common/index/ControlValueAccessor-interface.html).
891
- We can't apply `[(ngModel)]` to our custom components until we write a suitable *value accessor*,
933
+
934
+ The details are specific to each kind of element and therefore the `NgModel` directive only works for specific form elements,
935
+ such as the input text box, that are supported by a [ControlValueAccessor](../api/forms/index/ControlValueAccessor-interface.html).
936
+
937
+ We can't apply `[(ngModel)]` to a custom component until we write a suitable *value accessor*,
892
938
a technique that is beyond the scope of this chapter.
939
+ That's something we might want to do for an Angular component or a WebComponent whose API we can't control.
940
+
941
+ It's completely unnecessary for an Angular component that we _do_ control ... because we can name the value and event properties
942
+ to suit Angular's basic [two-way binding syntax](#two-way) and skip `NgModel` altogether.
893
943
894
944
:marked
895
- Separate `ngModel` bindings is an improvement. We can do better.
945
+ Separate `ngModel` bindings is an improvement over binding to the element's native properties . We can do better.
896
946
897
947
We shouldn't have to mention the data property twice. Angular should be able to capture the component’s data property and set it
898
- with a single declaration — which it can with the `[( )]` syntax:
948
+ with a single declaration — which it can with the `[(ngModel )]` syntax:
899
949
+ makeExample('template-syntax/ts/app/app.component.html' , 'NgModel-1' )( format ="." )
900
-
901
- .l-sub-section
902
- :marked
903
- `[(ngModel)]` is a specific example of a more general pattern in which Angular "de-sugars" the `[(x)]` syntax
904
- into an `x` input property for property binding and an `xChange` output property for event binding.
905
- Angular constructs the event property binding's template statement by appending `=$event`
906
- to the literal string of the template expression.
907
-
908
- > <span style="font-family:courier">[(_x_)]="_e_" <==> [_x_]="_e_" (<i>x</i>Change)="_e_=$event"</span>
909
-
910
- We can write a two-way binding directive of our own to exploit this behavior.
911
-
912
950
:marked
913
951
Is `[(ngModel)]` all we need? Is there ever a reason to fall back to its expanded form?
914
952
915
- The `[( )]` syntax can only _set_ a data-bound property.
953
+ The `[(ngModel )]` syntax can only _set_ a data-bound property.
916
954
If we need to do something more or something different, we need to write the expanded form ourselves.
917
955
918
956
Let's try something silly like forcing the input value to uppercase:
@@ -931,8 +969,8 @@ figure.image-display
931
969
The community contributed many more, and countless private directives
932
970
have been created for internal applications.
933
971
934
- We don’t need many of those directives in Angular 2 .
935
- Quite often we can achieve the same results with the more capable and expressive Angular 2 binding system.
972
+ We don’t need many of those directives in Angular.
973
+ Quite often we can achieve the same results with the more capable and expressive Angular binding system.
936
974
Why create a directive to handle a click when we can write a simple binding such as this?
937
975
+ makeExample('template-syntax/ts/app/app.component.html' , 'event-binding-1' )( format ="." )
938
976
:marked
@@ -1203,7 +1241,7 @@ block remember-the-brackets
1203
1241
1204
1242
:marked
1205
1243
### Expanding `*ngSwitch`
1206
- A similar transformation applies to `*ngSwitch`. We can de-sugar the syntax ourselves.
1244
+ A similar transformation applies to `*ngSwitch`. We can unfold the syntax ourselves.
1207
1245
Here's an example, first with `*ngSwitchCase` and `*ngSwitchDefault` and then again with `<template>` tags:
1208
1246
+ makeExample('template-syntax/ts/app/app.component.html' , 'NgSwitch-expanded' )( format ="." )
1209
1247
:marked
@@ -1241,14 +1279,18 @@ figure.image-display
1241
1279
1242
1280
A **template reference variable** is a reference to a DOM element or directive within a template.
1243
1281
1244
- It can be used with native DOM elements but also with Angular 2 components — in fact, it will work with any custom web component.
1282
+ It can be used with native DOM elements but also with Angular components — in fact, it will work with any custom web component.
1245
1283
1246
1284
:marked
1247
1285
### Referencing a template reference variable
1248
1286
1249
- We can reference a template reference variable on the same element, on a sibling element, or on
1250
- any child elements.
1287
+ We can refer to a template reference variable _anywhere_ in the current template.
1288
+ .l-sub-section
1289
+ :marked
1290
+ Do not define the same variable name more than once in the same template.
1291
+ The runtime value will be unpredictable.
1251
1292
1293
+ :marked
1252
1294
Here are two other examples of creating and consuming a Template reference variable:
1253
1295
+ makeExample('template-syntax/ts/app/app.component.html' , 'ref-phone' )( format ="." )
1254
1296
:marked
0 commit comments