@@ -56,11 +56,6 @@ a#intro
56
56
the form controls and pull user-changed values back out. The component can
57
57
observe changes in form control state and react to those changes.
58
58
59
- One advantage of working with the form control objects directly is that
60
- value and validity updates are always synchronous. This contrasts with
61
- template-driven forms, which must update asynchronously because they
62
- delegate operations to a directive running in the template.
63
-
64
59
In keeping with the reactive paradigm, the component
65
60
preserves the immutability of the _data model_,
66
61
treating it as a pure source of original values.
@@ -133,7 +128,7 @@ a#create-component
133
128
Make a new file called
134
129
`hero-detail.component.ts` in the `app` directory and import these symbols:
135
130
136
- + makeExample('reactive-forms/ts/app/hero-detail.component.ts' , 'reactive-comp- imports' ,'app/hero-detail.component.ts' )( format ="." )
131
+ + makeExample('reactive-forms/ts/app/hero-detail-1 .component.ts' , 'imports' ,'app/hero-detail.component.ts' )( format ="." )
137
132
138
133
:marked
139
134
Now enter the `@Component` decorator that specifies the `HeroDetailComponent` metadata:
@@ -146,8 +141,12 @@ a#create-component
146
141
such as when specifying the `templateUrl`.
147
142
148
143
Next, create an exported `HeroDetailComponent` class with a `FormControl`.
144
+ Notice that the `FormControl` is within a `FormGroup`. While you don't
145
+ _have_ to put a `FormControl` in a `FormGroup` for it to work, forms
146
+ usually contain multiple controls and grouping them offers advantages
147
+ you'll learn later in this guide.
149
148
150
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'v1' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
149
+ + makeExample('reactive-forms/ts/app/hero-detail-1 .component.ts' , 'v1' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
151
150
152
151
:marked
153
152
Here you are creating a `FormGroup` called `heroForm` with a child `FormControl` called `name`.
@@ -161,8 +160,8 @@ a#create-component
161
160
162
161
.l-sub-section
163
162
:marked
164
- Validators won't be covered at all in this guide.
165
- Learn about them in the [Form Validation](../cookbook/form-validation.html) cookbook.
163
+ Validators aren't covered at all in this guide.
164
+ Read about them in the [Form Validation](../cookbook/form-validation.html) cookbook.
166
165
167
166
.l-main-section
168
167
a#create-template
@@ -287,7 +286,10 @@ a#formbuilder
287
286
The `FormBuilder` class helps reduce repetition and
288
287
clutter by handling details of control creation for you.
289
288
290
- You already imported `FormBuilder` into `hero-detail.component.ts`.
289
+ To use `FormBuilder`, you need to import it into `hero-detail.component.ts`:
290
+ + makeExample('reactive-forms/ts/app/hero-detail-2.component.ts' , 'imports' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
291
+
292
+ :marked
291
293
Use it now to refactor the `HeroDetailComponent` into something that's a little easier to read and write,
292
294
by following this plan:
293
295
@@ -297,7 +299,7 @@ a#formbuilder
297
299
* Call `createForm` in the constructor.
298
300
299
301
The revised `HeroDetailComponent` looks like this:
300
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'v2' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
302
+ + makeExample('reactive-forms/ts/app/hero-detail-2 .component.ts' , 'v2' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
301
303
302
304
:marked
303
305
`FormBuilder.group` is a factory method that creates a `FormGroup`.
@@ -309,10 +311,17 @@ a#formbuilder
309
311
310
312
:marked
311
313
### More FormControls
312
- A hero has more than a name. A hero has an address too.
313
- Add some address `FormControls` to the `heroForm` as follows.
314
+ A hero has more than a name. A hero has an address too. You already have address data
315
+ in `data-model.ts`, so add it to the imports so you can use it:
314
316
315
- + makeExample('reactive-forms/ts/app/hero-detail-versions.component.ts' , 'v3' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
317
+ + makeExample('reactive-forms/ts/app/hero-detail-3.component.ts' , 'imports' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
318
+
319
+ :marked
320
+ Add some address `FormControls` to the `heroForm` as follows, being sure to
321
+ also declare `states`. This allows you to populate the state select with
322
+ the states in `data-model.ts`.
323
+
324
+ + makeExample('reactive-forms/ts/app/hero-detail-3.component.ts' , 'v3' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
316
325
317
326
:marked
318
327
Then add corresponding markup in `hero-detail.component.html`
@@ -344,7 +353,7 @@ a#grouping
344
353
Let that be the parent `FormGroup`.
345
354
Use `FormBuilder` again to create a child `FormGroup` that encapsulates the address controls;
346
355
assign the result to a new `address` property of the parent `FormGroup`.
347
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'v4' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
356
+ + makeExample('reactive-forms/ts/app/hero-detail-4 .component.ts' , 'v4' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
348
357
349
358
:marked
350
359
You’ve changed the structure of the form controls in the component class;
@@ -464,7 +473,7 @@ a#data-model-form-model
464
473
:marked
465
474
Here, again, is the component's `FormGroup` definition.
466
475
467
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'hero-form-model' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
476
+ + makeExample('reactive-forms/ts/app/hero-detail-5 .component.ts' , 'hero-form-model' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
468
477
:marked
469
478
There are two significant differences between these models:
470
479
@@ -478,8 +487,16 @@ a#data-model-form-model
478
487
479
488
:marked
480
489
Take a moment to refactor the _address_ `FormGroup` definition for brevity and clarity as follows:
481
- + makeExample('reactive-forms/ts/app/hero-detail-versions.component.ts' , 'address-form-group' )( format ="." )
490
+ + makeExample('reactive-forms/ts/app/hero-detail-6.component.ts' , 'address-form-group' )( format ="." )
491
+
482
492
:marked
493
+ Also be sure to update the imports so that you can use the `Hero` object:
494
+ + makeExample('reactive-forms/ts/app/hero-detail-5.component.ts' , 'imports' )( format ="." )
495
+
496
+ :marked
497
+ # Ward, `hero-detail-5.component.ts` is where `@Input() hero: Hero;`
498
+ # shows up for the first time, but I don't understand it or know where
499
+ # I should mention it. It seems like this is the general area, but we don't demonstrate it.
483
500
484
501
.l-main-section
485
502
a#set-data
@@ -493,7 +510,7 @@ a#set-data
493
510
With **`setValue`**, you assign _every_ form control value _at once_
494
511
by passing in a data object whose properties exactly match the _form model_ behind the `FormGroup`.
495
512
496
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'set-value' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
513
+ + makeExample('reactive-forms/ts/app/hero-detail-6 .component.ts' , 'set-value' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
497
514
:marked
498
515
The `setValue` method checks the data object thoroughly before assigning any form control values.
499
516
@@ -509,15 +526,15 @@ a#set-data
509
526
510
527
You can only show the hero's first address and you must account for the possibility that the `hero` has no addresses at all.
511
528
This explains the conditional setting of the `address` property in the data object argument:
512
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'set-value-address' )( format ="." )
529
+ + makeExample('reactive-forms/ts/app/hero-detail-6 .component.ts' , 'set-value-address' )( format ="." )
513
530
514
531
:marked
515
532
### _patchValue_
516
533
With **`patchValue`**, you can assign values to specific controls in a `FormGroup`
517
534
by supplying an object of key/value pairs for just the controls of interest.
518
535
519
536
This example sets only the form's `name` control.
520
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'patch-value' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
537
+ + makeExample('reactive-forms/ts/app/hero-detail-5 .component.ts' , 'patch-value' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
521
538
522
539
:marked
523
540
With **`patchValue`** you have more flexibility to cope with wildly divergent data and form models.
@@ -558,9 +575,15 @@ a#set-data
558
575
control values from the previous hero are cleared and
559
576
status flags are restored to the _pristine_ state.
560
577
578
+ In order to use `ngOnChanges`, add it to the `hero-detail.component.ts`
579
+ imports.
580
+
581
+ + makeExample('reactive-forms/ts/app/hero-detail-5.component.ts' , 'imports' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
582
+
583
+ :marked
561
584
Here's what `ngOnChanges` should look like:
562
585
563
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'set-value-on-changes' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
586
+ + makeExample('reactive-forms/ts/app/hero-detail-6 .component.ts' , 'set-value-on-changes' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
564
587
565
588
a#hero-list
566
589
:marked
@@ -611,7 +634,11 @@ a#form-array
611
634
An _address_ `FormGroup` can display one `Address`.
612
635
An Angular `FormArray` can display an array of _address_ `FormGroups`.
613
636
614
- To work with a `FormArray` you do the following:
637
+ To get access to the `FormArray` class, import it into `hero-detail.component.ts`:
638
+ + makeExample('reactive-forms/ts/app/hero-detail-7.component.ts' , 'imports' ,'app/hero-detail.component.ts (excerpt)' )( format ="." )
639
+
640
+ :marked
641
+ To _work_ with a `FormArray` you do the following:
615
642
1. Define the items (`FormControls` or `FormGroups`) in the array.
616
643
1. Initialize the array with items created from data in the _data model_.
617
644
1. Add and remove items as the user requires.
@@ -621,15 +648,15 @@ a#form-array
621
648
622
649
You’ll need to redefine the form model in the `HeroDetailComponent` constructor,
623
650
which currently only displays the first hero address in an _address_ `FormGroup`.
624
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'address-form-group' )( format ="." )
651
+ + makeExample('reactive-forms/ts/app/hero-detail-6 .component.ts' , 'address-form-group' )( format ="." )
625
652
626
653
:marked
627
654
### From _address_ to _secret lairs_
628
655
629
656
From the user's point of view, heroes don't have _addresses_.
630
657
_Addresses_ are for mere mortals. Heroes have _secret lairs_!
631
658
Replace the _address_ `FormGroup` definition with a _secretLairs_ `FormArray` definition:
632
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'secretLairs-form-array' )( format ="." )
659
+ + makeExample('reactive-forms/ts/app/hero-detail-7 .component.ts' , 'secretLairs-form-array' )( format ="." )
633
660
634
661
.alert.is-helpful
635
662
:marked
@@ -652,7 +679,7 @@ a#form-array
652
679
653
680
The following method replaces the _secretLairs_ `FormArray` with a new `FormArray`,
654
681
initialized by an array of hero address `FormGroups`.
655
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'set-addresses' )( format ="." )
682
+ + makeExample('reactive-forms/ts/app/hero-detail-7 .component.ts' , 'set-addresses' )( format ="." )
656
683
657
684
:marked
658
685
Notice that you replace the previous `FormArray` with the **`FormGroup.setControl` method**, not with `setValue`.
@@ -665,7 +692,7 @@ a#form-array
665
692
666
693
Use the `FormGroup.get` method to acquire a reference to that `FormArray`.
667
694
Wrap the expression in a `secretLairs` convenience property for clarity and re-use.
668
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'get-secret-lairs' ,'app/hero-detail.component.ts (secretLayers property)' )( format ="." )
695
+ + makeExample('reactive-forms/ts/app/hero-detail-7 .component.ts' , 'get-secret-lairs' ,'app/hero-detail.component.ts (secretLayers property)' )( format ="." )
669
696
670
697
:marked
671
698
### Display the _FormArray_
@@ -699,7 +726,7 @@ a#form-array
699
726
### Add a new lair to the _FormArray_
700
727
701
728
Add an `addLair` method that gets the _secretLairs_ `FormArray` and appends a new _address_ `FormGroup` to it.
702
- + makeExample('reactive-forms/ts/app/hero-detail-versions .component.ts' , 'add-lair' ,'app/hero-detail.component.ts (addLair method)' )( format ="." )
729
+ + makeExample('reactive-forms/ts/app/hero-detail-7 .component.ts' , 'add-lair' ,'app/hero-detail.component.ts (addLair method)' )( format ="." )
703
730
704
731
:marked
705
732
Place a button on the form so the user can add a new _secret lair_ and wire it to the component's `addLair` method.
@@ -807,7 +834,7 @@ figure.image-display
807
834
Instead, it must prepare `saveHero` whose values derive from a combination of original hero values (the `hero.id`)
808
835
and deep copies of the potentially-changed form model values.
809
836
810
- #Ward, stop lecturing#
837
+ # Ward, stop lecturing :D
811
838
812
839
+ makeExample('reactive-forms/ts/app/hero-detail.component.ts' , 'prepare-save-hero' ,'app/hero-detail.component.ts (prepareSaveHero)' )( format ="." )
813
840
0 commit comments