@@ -16,11 +16,11 @@ a#toc
16
16
- [Import the _ReactiveFormsModule_](#import)
17
17
- [Update the app to use the form component](#update)
18
18
- [Introduction to _FormBuilder_](#formbuilder)
19
- - [Group _FormControls_ ](#grouping)
19
+ - [Nested FormGroups ](#grouping)
20
20
- [Inspect _FormControl_ properties](#properties)
21
21
- [Set form model data using _setValue_ and _patchValue_](#set-data)
22
22
- [Use _FormArray_ to present an array of _FormGroups_](#form-array)
23
- - [Watch control changes](#watch -control)
23
+ - [Observe control changes](#observe -control)
24
24
- [Save form data](#save)
25
25
26
26
Try the <live-example plnkr="final" title="Reactive Forms (final) in Plunker">Reactive Forms live-example</live-example>.
@@ -85,42 +85,22 @@ a#intro
85
85
You don't push and pull data values. Angular handles that for you with `ngModel`.
86
86
Angular updates the mutable _data model_ with user changes as they happen.
87
87
88
- Both data binding and the mutable _data model_ are contrary to reactive principles.
89
- In fact, the `ngModel` directive is only available in the `FormsModule`, not in the `ReactiveFormsModule`.
90
-
88
+ When writing in a reactive style, you determine the timing and flow of data between
89
+ the data model and the screen. You rarely, if ever, use two-way data binding.
90
+ For this reason, the ngModel directive is not part of the ReactiveFormsModule.
91
+
91
92
These differences reflect two architectural paradigms,
92
93
with their own strengths and weaknesses,
93
94
and you are free to choose between them.
94
95
95
96
The balance of this _reactive forms_ guide assumes the _reactive_ paradigm and
96
- concentrates exclusively on the reactive forms technique . For
97
+ concentrates exclusively on the reactive forms techniques . For
97
98
information on _template driven forms_, see the [Template Guide](forms.html).
98
99
99
- You'll learn about reactive forms by building one from scratch,
100
- with instances of the Angular form classes.
101
-
102
- ### Essential form classes
103
-
104
- Before you begin, it may be helpful to read a brief description of the core form classes.
105
-
106
- * [_AbstractControl_](../api/forms/index/AbstractControl-class.html-class.html "API Reference: AbstractControl")
107
- is the abstract base class for the three concrete form control classes:
108
- `FormControl`, `FormGroup`, and `FormArray`.
109
- It provides their common behaviors and properties, some of which are _observable_.
110
-
111
- * [_FormControl_](../api/forms/index/FormControl-class.html "API Reference: FormControl")
112
- tracks the value and validity status of an _individual_ form control.
113
- It corresponds to an HTML form control such as an input box or selector.
114
-
115
- * [_FormGroup_](../api/forms/index/FormGroup-class.html "API Reference: FormGroup")
116
- tracks the value and validity state of a _group_ of `AbstractControl` instances.
117
- The group's properties include its child controls.
118
- The top-level form in your component is a `FormGroup`.
119
-
120
- * [_FormArray_](../api/forms/index/FormArray-class.html "API Reference: FormArray")
121
- tracks the value and validity state of a numerically indexed _array_ of `AbstractControl` instances.
100
+ You'll learn about reactive forms by building one from scratch.
122
101
123
- You'll learn more about these classes as you build your first reactive form.
102
+ In the next section, you'll prepare your project for reactive forms.
103
+ Then you'll [learn about the Angular form classes](#essentials) and how to use them in a reactive form.
124
104
125
105
.l-main-section
126
106
a#setup
@@ -170,7 +150,7 @@ a#create-component
170
150
+ makeExample('reactive-forms/ts/app/hero-detail-versions.component.ts' , 'v1' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
171
151
172
152
:marked
173
- Inside the `FormGroup`, called `heroForm`, is a `FormControl` called `name`.
153
+ Here you are creating a `FormGroup` called `heroForm` with a child `FormControl` called `name`.
174
154
It will be bound in the template to an HTML `input` box for the hero name.
175
155
176
156
A `FormControl` constructor accepts three, optional arguments:
@@ -195,9 +175,11 @@ a#create-template
195
175
:marked
196
176
The `novalidate` attribute in the `<form>` element prevents the browser
197
177
from attempting native HTML validations.
198
- The `[formGroup]="heroForm"` tells Angular that the form element
199
- is associated with the `heroForm` property of the component class.
200
- The `formControlName="name"` associates the `input` element with the `name` control inside the `heroForm`.
178
+
179
+ `formGroup` is a reactive form directive that takes an existing
180
+ `FormGroup` instance and associates it with an HTML element.
181
+ In this case, it will associate the `FormGroup` we saved as
182
+ `heroForm` with the form element.
201
183
202
184
.l-sub-section
203
185
:marked
@@ -210,9 +192,8 @@ a#import
210
192
:marked
211
193
## Import the _ReactiveFormsModule_
212
194
213
- The `HeroDetailComponent` template uses directives from
214
- the `ReactiveFormsModule` in the `@angular/forms` library
215
- so you must add it to the `imports` array of the `NgModule` that declares that component.
195
+ The HeroDetailComponent template uses `formGroup` and `formControlName`
196
+ directives from the `ReactiveFormsModule`.
216
197
217
198
In this sample, you declare the `HeroDetailComponent` in the `AppModule`.
218
199
Therefore, do the following three things in `app.module.ts`:
@@ -230,6 +211,31 @@ a#update
230
211
Revise the `AppComponent` template so it displays the `HeroDetailComponent`.
231
212
+ makeExample('reactive-forms/ts/app/app.component.1.ts' , '' ,'app/app.component.ts' )( format ="." )
232
213
214
+ a#essentials
215
+ :marked
216
+ ### Essential form classes
217
+ It may be helpful to read a brief description of the core form classes.
218
+
219
+ * [_AbstractControl_](../api/forms/index/AbstractControl-class.html-class.html "API Reference: AbstractControl")
220
+ is the abstract base class for the three concrete form control classes:
221
+ `FormControl`, `FormGroup`, and `FormArray`.
222
+ It provides their common behaviors and properties, some of which are _observable_.
223
+
224
+ * [_FormControl_](../api/forms/index/FormControl-class.html "API Reference: FormControl")
225
+ tracks the value and validity status of an _individual_ form control.
226
+ It corresponds to an HTML form control such as an input box or selector.
227
+
228
+ * [_FormGroup_](../api/forms/index/FormGroup-class.html "API Reference: FormGroup")
229
+ tracks the value and validity state of a _group_ of `AbstractControl` instances.
230
+ The group's properties include its child controls.
231
+ The top-level form in your component is a `FormGroup`.
232
+
233
+ * [_FormArray_](../api/forms/index/FormArray-class.html "API Reference: FormArray")
234
+ tracks the value and validity state of a numerically indexed _array_ of `AbstractControl` instances.
235
+
236
+ You'll learn more about these classes as you work through this guide.
237
+
238
+
233
239
:marked
234
240
### Style the app
235
241
You used bootstrap CSS classes in the template HTML of both the `AppComponent` and the `HeroDetailComponent`.
@@ -270,7 +276,6 @@ figure.image-display
270
276
Great! You have the basics of a form.
271
277
272
278
In real life apps, forms get big fast.
273
- The way you are creating `FormControls` currently is both tedious and hard to maintain.
274
279
`FormBuilder` makes form development and maintenance easier.
275
280
276
281
@@ -288,7 +293,7 @@ a#formbuilder
288
293
289
294
* Explicitly declare the type of the `heroForm` property to be `FormGroup`; you'll initialize it later.
290
295
* Inject a `FormBuilder` into the constructor.
291
- * Add a new `createForm` method that uses the `FormBuilder` to define the `heroForm`.
296
+ * Add a new method that uses the `FormBuilder` to define the `heroForm`; call it `createForm `.
292
297
* Call `createForm` in the constructor.
293
298
294
299
The revised `HeroDetailComponent` looks like this:
@@ -326,12 +331,13 @@ a#formbuilder
326
331
.l-main-section
327
332
a#grouping
328
333
:marked
329
- ### Group FormControls
334
+ ### Nested FormGroups
330
335
331
336
This form is getting big and unwieldy. You can group some of the related `FormControls`
332
- into another `FormGroup`. The `street`, `city`, `state`, and `zip` are properties
337
+ into a nested `FormGroup`. The `street`, `city`, `state`, and `zip` are properties
333
338
that would make a good _address_ `FormGroup`.
334
- Grouping in this way allows you to mirror the hierarchical structure of the data model
339
+ Nesting groups and controls in this way allows you to
340
+ mirror the hierarchical structure of the data model
335
341
and helps track validation and state for related sets of controls.
336
342
337
343
You used the `FormBuilder` to create one `FormGroup` in this component called `heroForm`.
@@ -403,7 +409,7 @@ table(width="100%")
403
409
td <code >myControl.status</code >
404
410
td
405
411
:marked
406
- whether the `FormControl` is `valid`,
412
+ the validity of a `FormControl`. Possible values: `valid`,
407
413
`invalid`, `pending`, or `disabled`.
408
414
tr
409
415
td <code >myControl.pristine</code >
@@ -446,9 +452,6 @@ a#data-model-form-model
446
452
447
453
2. User changes flow from the DOM elements to the _form model_, not to the _data model_.
448
454
The form controls never update the _data model_.
449
- In the reactive paradigm, the data model is presumed to be _immutable_
450
- and it's your responsibility to preserve that immutability constraint.
451
- Kara, Deborah suggested running this by you. Could you confirm that this is the case?
452
455
453
456
The _form_ and _data_ model structures need not match exactly.
454
457
You often present a subset of the _data model_ on a particular screen.
@@ -482,7 +485,9 @@ a#data-model-form-model
482
485
a#set-data
483
486
:marked
484
487
## Populate the form model with _setValue_ and _patchValue_
485
- You can initialize control values in a `FormGroup` using `setValue` or `patchValue`.
488
+ Previously you created a control and initialized its value at the same time.
489
+ You can also initialize or reset the values _later_ with the
490
+ `setValue` and `patchValue` methods.
486
491
487
492
### _setValue_
488
493
With **`setValue`**, you assign _every_ form control value _at once_
@@ -491,9 +496,13 @@ a#set-data
491
496
+ makeExample('reactive-forms/ts/app/hero-detail-versions.component.ts' , 'set-value' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
492
497
:marked
493
498
The `setValue` method checks the data object thoroughly before assigning any form control values.
494
- It rejects a data object that doesn't match the `FormGroup` structure.
495
- It rejects a data object if it is missing values for any control in the group.
496
- It does return helpful errors.
499
+
500
+ - It rejects a data object that doesn't match the `FormGroup` structure.
501
+ - It rejects a data object if it is missing values for any control in the group.
502
+ - It returns helpful error messages.
503
+
504
+ If you have a typo or nested controls incorrectly, `setValue` will catch
505
+ the error and report it clearly. `patchValue` will fail silently.
497
506
498
507
Notice that you can _almost_ use the entire `hero` as the argument to `setValue`
499
508
because its shape is similar to the component's `FormGroup` structure.
@@ -512,7 +521,8 @@ a#set-data
512
521
513
522
:marked
514
523
With **`patchValue`** you have more flexibility to cope with wildly divergent data and form models.
515
- But unlike `setValue`, `patchValue` cannot check for missing control values and does not return errors.
524
+ But unlike `setValue`, `patchValue` cannot check for missing control
525
+ values and does not throw helpful errors.
516
526
517
527
### When to set form model values (_ngOnChanges_)
518
528
@@ -654,7 +664,7 @@ a#form-array
654
664
The `HeroDetailComponent` should be able to display, add, and remove items from the _secretLairs_ `FormArray`.
655
665
656
666
Use the `FormGroup.get` method to acquire a reference to that `FormArray`.
657
- Wrap the expression in a `secretLairs` convenience property for clairity and re-use.
667
+ Wrap the expression in a `secretLairs` convenience property for clarity and re-use.
658
668
+ makeExample('reactive-forms/ts/app/hero-detail-versions.component.ts' , 'get-secret-lairs' ,'app/hero-detail.component.ts (secretLayers property)' )( format ="." )
659
669
660
670
:marked
@@ -675,7 +685,7 @@ a#form-array
675
685
1. The source of the repeated items is the `FormArray.controls`, not the `FormArray` itself.
676
686
Each control is an _address_ `FormGroup`, exactly what the previous (now repeated) template HTML expected.
677
687
678
- 1. Each repeated `FormGroup` needs a unique `FormGroupName ` which must be the index of the `FormGroup` in the `FormArray`.
688
+ 1. Each repeated `FormGroup` needs a unique `formGroupName ` which must be the index of the `FormGroup` in the `FormArray`.
679
689
You'll re-use that index to compose a unique label for each address.
680
690
681
691
Here's the skeleton for the _secret lairs_ section of the HTML template:
@@ -724,9 +734,9 @@ figure.image-display
724
734
For extra credit, write a `removeLair` method and wire it to a button on the repeating address HTML.
725
735
726
736
.l-main-section
727
- a#watch -control
737
+ a#observe -control
728
738
:marked
729
- ## Watch control changes
739
+ ## Observe control changes
730
740
731
741
Angular calls `ngOnChanges` when the user picks a hero in the parent `HeroListComponent`.
732
742
Picking a hero changes the `HeroDetailComponent.hero` input property.
0 commit comments