@@ -17,17 +17,17 @@ include ../_util-fns
17
17
18
18
We will build a simple form from scratch, one step at a time. Along the way we'll learn
19
19
20
- - How to build an Angular form with a component and template
20
+ - to build an Angular form with a component and template
21
21
22
- - The `ngModel` two-way data binding syntax for reading and writing values to input controls
22
+ - two-way data binding with `[(ngModel)]` syntax for reading and writing values to input controls
23
23
24
- - The `ngControl` directive to track the change state and validity of form controls
24
+ - using `ngControl` to track the change state and validity of form controls
25
25
26
- - The special CSS classes that `ngControl` adds to form controls and how we can use them to provide strong visual feedback
26
+ - the special CSS classes that `ngControl` adds to form controls and how we can use them to provide strong visual feedback
27
27
28
- - How to display validation errors to users and enable/disable form controls
28
+ - displaying validation errors to users and enable/disable form controls
29
29
30
- - How to share information across controls with template local variables
30
+ - sharing information among controls with template local variables
31
31
32
32
[Live Example](/resources/live-examples/forms/ts/plnkr.html)
33
33
.l-main-section
@@ -75,7 +75,7 @@ figure.image-display
75
75
1. Create the `Hero` model class
76
76
1. Create the component that controls the form
77
77
1. Create a template with the initial form layout
78
- 1. Add the **ngModel** directive to each form input control
78
+ 1. Bind data properties to each form input control with the `ngModel` two-way data binding syntax
79
79
1. Add the **ngControl** directive to each form input control
80
80
1. Add custom CSS to provide visual feedback
81
81
1. Show and hide validation error messages
240
240
<a id =" ngModel" ></a >
241
241
.l-main-section
242
242
:marked
243
- ## Two-way data binding with *** ngModel**
243
+ ## Two-way data binding with **ngModel**
244
244
Running the app right now would be disappointing.
245
245
246
246
figure.image-display
@@ -255,7 +255,7 @@ figure.image-display
255
255
Now we need to display, listen, and extract at the same time.
256
256
257
257
We could use those techniques again in our form.
258
- Instead we'll introduce something new, the `NgModel` directive , that
258
+ Instead we'll introduce something new, the `[(ngModel)]` syntax , that
259
259
makes binding our form to the model super-easy.
260
260
261
261
Find the `<input>` tag for the "Name" and update it like this
@@ -349,41 +349,43 @@ figure.image-display
349
349
## Track change-state and validity with **ngControl**
350
350
351
351
A form isn't just about data binding. We'd also like to know the state of the controls on our form.
352
- The `NgControl` directive keeps track of control state for us.
353
352
354
- .callout.is-helpful
355
- header NgControl requires Form
356
- :marked
357
- The `NgControl` is one of a family of `NgForm` directives that can only be applied to
358
- a control within a `<form`> tag.
359
- :marked
360
- Our application can ask an `NgControl` if the user touched the control,
353
+ By setting `ngControl` we create a directive that can tell if the user touched the control,
361
354
if the value changed, or if the value became invalid.
362
355
363
- `NgControl` doesn't just track state; it updates the control with special
356
+ This directive doesn't just track state; it updates the control with special
364
357
Angular CSS classes from the set we listed above.
365
358
We can leverage those class names to change the appearance of the
366
359
control and make messages appear or disappear.
367
360
368
361
We'll explore those effects soon. Right now
369
- we should **add `ngControl`to all three form controls**,
362
+ we should **add `ngControl` to all three form controls**,
370
363
starting with the *Name* input box
371
364
+ makeExample('forms/ts/app/hero-form.component.html' , 'ngControl-1' , 'app/hero-form.component.html (excerpt)' )( format ="." )
372
365
:marked
373
- Be sure to assign a unique name to each `ngControl` directive .
366
+ We set this particular `ngControl` to " name" which makes sense for our app. Any unique value will do .
374
367
375
368
.l-sub-section
376
369
:marked
377
- Angular registers controls under their `ngControl` names
378
- with the `NgForm`.
379
- We didn't add the `NgForm` directive explicitly but it's here
380
- and we'll talk about it [later in this chapter](#ngForm).
370
+ Internally Angular creates `Controls` and registers them under their `ngControl` names
371
+ with an `NgForm` directive that Angular attached to the `<form>` tag.
372
+ We'll talk about `NgForm` [later in the chapter](#ngForm).
373
+
374
+ The `ngControl` *attribute* in our template actually maps to the
375
+ [NgControlName](../api/common/NgControlName-directive.html) directive.
376
+ There is also a `NgControl` *abstract* directive which is *not the same thing*.
377
+ We often ignore this technical distinction and refer to `NgControlName` more conveniently (albeit incorrectly) as the *NgControl* directive.
378
+
379
+ While we're under the hood, we might as well note that the `ngModel` in the
380
+ two-way binding syntax is now a property of the the `NgControlName` directive.
381
+ The `NgModel` directive is no longer involved. We only need one directive to manage the DOM element
382
+ and there is no practical difference in the way either directive handles data binding.
381
383
382
384
.l-main-section
383
385
:marked
384
386
## Add Custom CSS for Visual Feedback
385
387
386
- ` NgControl` doesn't just track state.
388
+ The * NgControl* directive doesn't just track state.
387
389
It updates the control with three classes that reflect the state.
388
390
389
391
table
@@ -468,13 +470,19 @@ figure.image-display
468
470
'name-with-error-msg' ,
469
471
'app/hero-form.component.html (excerpt)' )( format ="." )
470
472
:marked
471
- When we added the `ngControl` directive, we bound it to the the model's `name` property.
472
-
473
- Here we initialize a template local variable (`name`) with the value "ngForm" (`#name="ngForm"`).
474
- Angular recognizes that syntax and re-sets the `name` local template variable to the
475
- `ngControl` directive instance.
476
- In other words, the `name` local template variable becomes a handle on the `ngControl` object
477
- for this input box.
473
+ We need a template local variable to access the input box's Angular control from within the template.
474
+ Here we created a variable called `name` and gave it the value "ngForm".
475
+ .l-sub-section
476
+ :marked
477
+ Why "ngForm"?
478
+ A directive's [exportAs](/docs/ts/latest/api/core/DirectiveMetadata-class.html#!#exportAs) property
479
+ tells Angular how to link local variable to the directive.
480
+ We set `name` to `ngForm` because the `NgControlName` directive's `exportAs` property happens to be "ngForm".
481
+
482
+ This seems unintuitive at first until we realize that *all* control directives in the
483
+ Angular form family &mdash including `NgForm`, `NgModel`, `NgControlName` and `NgControlGroup` — *exportAs* "ngForm"
484
+ and we only ever apply *one* of these directives to an element tag.
485
+ Consistency rules!
478
486
479
487
Now we can control visibility of the "name" error message by binding properties of the `name` control to the message `<div >` element's `hidden` property.
480
488
+ makeExample('forms/ts/app/hero-form.component.html' ,
@@ -492,21 +500,7 @@ figure.image-display
492
500
Some folks find that behavior disconcerting. They only want to see the message when the user makes an invalid change.
493
501
Hiding the message while the control is "pristine" achieves that goal.
494
502
We'll see the significance of this choice when we [add a new hero](#new-hero) to the form.
495
- <a id =" ngForm" ></a >
496
- .l-sub-section
497
- :marked
498
- ### The NgForm directive
499
- We just set a template local variable with the value of an `NgForm` directive.
500
- Why did that work? We didn't add the **[`NgForm`](../api/core/NgForm-class.html) directive** explicitly.
501
-
502
- Angular added it surreptiously, wrapping it around the `<form>` element
503
503
504
- The `NgForm` directive supplements the `form` element with additional features.
505
- It collects `Controls` (elements identified by an `ngControl` directive)
506
- and monitors their properties including their validity.
507
- It also has its own `valid` property which is true only if every contained
508
- control is valid.
509
- :marked
510
504
The Hero *Alter Ego* is optional so we can leave that be.
511
505
512
506
Hero *Power* selection is required.
@@ -582,9 +576,22 @@ figure.image-display
582
576
We slipped in something extra there at the end! We defined a
583
577
template local variable, **`#heroForm`**, and initialized it with the value, "ngForm".
584
578
585
- The variable `heroForm` is now a handle to the `NgForm` directive that we [discussed earlier](#ngForm)
586
- This time `heroForm` remains a reference to the form as a whole.
579
+ The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole.
580
+ <a id =" ngForm" ></a >
581
+ .l-sub-section
582
+ :marked
583
+ ### The NgForm directive
584
+ What `NgForm` directive? We didn't add an [NgForm](../api/core/NgForm-class.html) directive!
585
+
586
+ Angular did. Angular creates and attaches an `NgForm` directive to the `<form>` tag automatically.
587
587
588
+ The `NgForm` directive supplements the `form` element with additional features.
589
+ It holds the controls we created for the elements with `ngControl` attributes
590
+ and monitors their properties including their validity.
591
+ It also has its own `valid` property which is true only *if every contained
592
+ control* is valid.
593
+
594
+ :marked
588
595
Later in the template we bind the button's `disabled` property to the form's over-all validity via
589
596
the `heroForm` variable. Here's that bit of markup:
590
597
+ makeExample('forms/ts/app/hero-form.component.html' , 'submit-button' )
@@ -658,8 +665,8 @@ figure.image-display
658
665
- A form component class with a `Component` decorator.
659
666
- The `ngSubmit` directive for handling the form submission.
660
667
- Template local variables such as `#heroForm`, `#name`, `#alter-ego` and `#power`.
661
- - The `ngModel` directive for two-way data binding.
662
- - The `ngControl` for validation and form element change tracking.
668
+ - The `[( ngModel)]` syntax for two-way data binding.
669
+ - The `ngControlName` directive for validation and form element change tracking.
663
670
- The local variable’s `valid` property on input controls to check if a control is valid and show/hide error messages.
664
671
- Controlling the submit button's enabled state by binding to `NgForm` validity.
665
672
- Custom CSS classes that provide visual feedback to users about invalid controls.
0 commit comments