Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit a432262

Browse files
wardbellkapunahelewong
authored andcommitted
docs(reactive-forms): Ward's tweaks on jan 23
1 parent 4ae9a92 commit a432262

File tree

3 files changed

+89
-75
lines changed

3 files changed

+89
-75
lines changed

public/docs/_examples/reactive-forms/ts/app/hero-detail-3.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ export class HeroDetailComponent3 {
1818
}
1919

2020
createForm() {
21+
// #docregion required
2122
this.heroForm = this.fb.group({
22-
// #docregion required
2323
name: ['', Validators.required ],
24-
// #enddocregion required
2524
});
25+
// #enddocregion required
2626
}
2727
}
2828
// #enddocregion v3

public/docs/_examples/reactive-forms/ts/app/hero-detail-4.component.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@ <h3><i>A FormGroup with multiple FormControls</i></h3>
2626
</div>
2727
<div class="form-group">
2828
<label>Super power:</label>
29-
<input type="radio" formControlName="power" value="flight">Flight
30-
<input type="radio" formControlName="power" value="x-ray vision">X-ray vision
31-
<input type="radio" formControlName="power" value="strength">Strength
29+
<label><input type="radio" formControlName="power" value="flight">Flight</label>
30+
<label><input type="radio" formControlName="power" value="x-ray vision">X-ray vision</label>
31+
<label><input type="radio" formControlName="power" value="strength">Strength</label>
3232
</div>
3333
<div class="checkbox">
3434
<label>
35-
<input type="checkbox" formControlName="sidekick">I have a sidekick.</label>
35+
<input type="checkbox" formControlName="sidekick">I have a sidekick.
36+
</label>
3637
</div>
3738
</form>
3839

public/docs/ts/latest/guide/reactive-forms.jade

Lines changed: 82 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ a#toc
2525
- [Use _FormArray_ to present an array of _FormGroups_](#form-array)
2626
- [Observe control changes](#observe-control)
2727
- [Save form data](#save)
28-
- [Appendix: Async vs. sync in Angular forms](a#appendix)
2928

3029
Try the <live-example plnkr="final" title="Reactive Forms (final) in Plunker">Reactive Forms live-example</live-example>.
3130

@@ -62,8 +61,9 @@ a#intro
6261
observe changes in form control state and react to those changes.
6362

6463
One advantage of working with form control objects directly is that value and validity updates
65-
are always synchronous and under your control.
66-
You won't encounter the timing issues that sometimes plague a template-driven form.
64+
are [always synchronous and under your control](#async-vs-sync "Async vs sync").
65+
You won't encounter the timing issues that sometimes plague a template-driven form
66+
and reactive forms can be easier to unit test.
6767

6868
In keeping with the reactive paradigm, the component
6969
preserves the immutability of the _data model_,
@@ -90,19 +90,52 @@ a#intro
9090
Angular updates the mutable _data model_ with user changes as they happen.
9191

9292
For this reason, the `ngModel` directive is not part of the ReactiveFormsModule.
93+
94+
While this means less code in the component class,
95+
[template-driven forms are asynchronous](#async-vs-sync "Async vs sync")
96+
which may complicate development in more advanced scenarios.
97+
98+
a#async-vs-sync
99+
:marked
100+
### Async vs. sync
101+
102+
Reactive forms are synchronous. Template-driven forms are asynchronous. It's a difference that matters.
103+
104+
In reactive forms, you create the entire form control tree in code.
105+
You can immediately update a value or drill down through the descendents of the parent form
106+
because all controls are always available.
107+
108+
Template-driven forms delegate creation of their form controls to directives.
109+
To avoid "_changed after checked_" errors,
110+
these directives take more than one cycle to build the entire control tree.
111+
That means you must wait a tick before manipulating any of the controls
112+
from within the component class.
93113

94-
These differences reflect two architectural paradigms,
95-
with their own strengths and weaknesses,
96-
and you are free to choose between them.
114+
For example, if you inject the form control with a `@ViewChild(NgForm)` query and examine it in the
115+
[`ngAfterViewInit` lifecycle hook](lifecycle-hooks.html#afterview "Lifecycle hooks guide: AfterView"),
116+
you'll discover that it has no children.
117+
You must wait a tick, using `setTimeout`, before you can
118+
extract a value from a control, test its validity, or set it to a new value.
119+
120+
The asynchrony of template-driven forms also complicates unit testing.
121+
You must wrap your test block in `async()` or `fakeAsync()` to
122+
avoid looking for values in the form that aren't there yet.
123+
With reactive forms, everything is available when you expect it to be.
124+
125+
### Which is better, reactive or template-driven?
97126

98-
The balance of this _reactive forms_ guide assumes the _reactive_ paradigm and
99-
concentrates exclusively on the reactive forms techniques. For
100-
information on _template driven forms_, see the [Template Guide](forms.html).
127+
Neither is "better".
128+
They're two different architectural paradigms,
129+
with their own strengths and weaknesses.
130+
Choose the approach that works best for you.
131+
You may decide to use both in the same application.
101132

102-
For a further comparison see [Appendix: Async vs. sync in Angular forms](#appendix).
133+
The balance of this _reactive forms_ guide explores the _reactive_ paradigm and
134+
concentrates exclusively on reactive forms techniques.
135+
For information on _template-driven forms_, see the [_Forms_](forms.html) guide.
103136

104137
In the next section, you'll set up your project for the reactive form demo.
105-
Then you'll [learn about the Angular form classes](#essentials) and how to use them in a reactive form.
138+
Then you'll learn about the [Angular form classes](#essentials) and how to use them in a reactive form.
106139

107140
.l-main-section
108141
a#setup
@@ -361,35 +394,42 @@ a#validators
361394
Though this guide doesn't go deeply into validations, here is one example that
362395
demonstrates the simplicity of using `Validators.required` in reactive forms.
363396

364-
First, be sure to import it:
397+
First, import the `Validators` symbol.
365398
+makeExample('reactive-forms/ts/app/hero-detail-3.component.ts', 'imports','app/hero-detail.component.ts (excerpt)')(format=".")
366399

367400
:marked
368-
Then, you can easily make the `name` `FormControl` required by supplying the `name`
369-
property in the class with an array that holds two arguments,
370-
the initial value for `name` and `Validators.required`. By contrast,
371-
in template driven forms, you must wrap validators in a directive.
372-
Reactive validators are simple, composable functions.
401+
To make the `name` `FormControl` required, replace the `name`
402+
property in the `FormGroup` with an array.
403+
The first item is the initial value for `name`;
404+
the second is the required validator, `Validators.required`.
373405

374406
+makeExample('reactive-forms/ts/app/hero-detail-3.component.ts', 'required','app/hero-detail.component.ts (excerpt)')(format=".")
375-
407+
.l-sub-section
408+
:marked
409+
Reactive validators are simple, composable functions.
410+
Configuring validation is harder in template-driven forms where you must wrap validators in a directive.
376411
:marked
377-
Now, by outputting the form's status in the template, you can see
378-
whether the form is `VALID` or `INVALID`. Add the following to the template:
412+
Update the diagnostic message at the bottom of the template to display the form's validity status.
379413

380414
+makeExample('reactive-forms/ts/app/hero-detail-3.component.html', 'form-value-json','app/hero-detail.component.html (excerpt)')(format=".")
381415

382416
:marked
383-
The browser displays the form's status according to `Validators.required`:
417+
The browser displays the following:
384418

385419
figure.image-display
386420
img(src="/resources/images/devguide/reactive-forms/validators-json-output.png" width="400px" alt="Single FormControl")
387421

388422
:marked
389-
`Validators.required` defaults
390-
to `INVALID` when the input has no value. Type into the input
391-
to watch the status change from `INVALID` to `VALID`.
423+
`Validators.required` is working. The status is `INVALID` because the input box has no value.
424+
Type into the input box to see the status change from `INVALID` to `VALID`.
425+
426+
In a real app, you'd replace the diagnosic message with a user-friendly experience.
392427

428+
.alert.is-critical
429+
:marked
430+
Kapunahele: Why not keep it throughout? I know it's a bit of work but it will be useful to see
431+
how you preserve `Validators.required` as you evolve the control tree.
432+
:marked
393433
Using `Validators.required` is optional for the rest of the guide.
394434
You may remove it as what follows does not use it.
395435

@@ -398,16 +438,15 @@ figure.image-display
398438

399439
:marked
400440
### More FormControls
401-
A hero has more than a name. A hero has an address, a super
402-
power and sometimes a sidekick too. You already have address data
403-
in `data-model.ts`, so add it to the imports so you can use it:
404-
441+
A hero has more than a name.
442+
A hero has an address, a super power and sometimes a sidekick too.
443+
444+
The address has a state property. The user will select a state with a `<select>` box and you'll populate
445+
the `<option>` elements with states. So import `states` from `data-model.ts`.
405446
+makeExample('reactive-forms/ts/app/hero-detail-4.component.ts', 'imports','app/hero-detail.component.ts (excerpt)')(format=".")
406447

407448
:marked
408-
Add some address `FormControls` to the `heroForm` as follows, being sure to
409-
also declare `states`. This allows you to populate the state select with
410-
the states in `data-model.ts`.
449+
Declare the `states` property and add some address `FormControls` to the `heroForm` as follows.
411450

412451
+makeExample('reactive-forms/ts/app/hero-detail-4.component.ts', 'v4','app/hero-detail.component.ts (excerpt)')(format=".")
413452

@@ -427,15 +466,18 @@ figure.image-display
427466
Angular `FormGroup` and `FormControl` properties in the component class.
428467

429468
:marked
430-
These new `FormControls` include text inputs, a select for the state,
431-
radio buttons, and a checkbox. In the class
432-
they are instantiated in the same way and in the template,
433-
each one is tied to the form control tree by specifiying
434-
the `FormControl` name using the `formControlName` directive.
435-
For more information about radio buttons, selects, and checkboxes,
436-
see the API reference for [RadioControlValueAccessor](api/forms/index/RadioControlValueAccessor-directive.html),
437-
[SelectControlValueAccessor](api/forms/index/SelectControlValueAccessor-directive.html),
438-
and [CheckboxControlValueAccessor](api/forms/index/CheckboxControlValueAccessor-directive.html).
469+
The revised template includes more text inputs, a select box for the `state`, radio buttons for the `power`,
470+
and a checkbox for the `sidekick`.
471+
472+
The component _class_ defines control properties without regard for their representation in the template.
473+
You define the `state`, `power`, and `sidekick` controls the same way you defined the `name` control.
474+
You tie these controls to the template HTML elements in the same way,
475+
specifiying the `FormControl` name with the `formControlName` directive.
476+
477+
See the API reference for more information about
478+
[radio buttons](api/forms/index/RadioControlValueAccessor-directive.html "API: RadioControlValueAccessor"),
479+
[selects](api/forms/index/SelectControlValueAccessor-directive.html "API: SelectControlValueAccessor"), and
480+
[checkboxes](api/forms/index/CheckboxControlValueAccessor-directive.html "API: CheckboxControlValueAccessor").
439481

440482
.l-main-section
441483
a#grouping
@@ -958,35 +1000,6 @@ figure.image-display
9581000
This is the final step in the demo.
9591001
Try the <live-example plnkr="final" title="Reactive Forms (final) in Plunker"></live-example>.
9601002

961-
a#appendix
962-
.l-main-section
963-
:marked
964-
## Appendix: Async vs. sync in Angular forms
965-
966-
In a reactive form you create the form control tree, also known as
967-
the form model. Because you aren't delegating the creation of the
968-
form controls to a directive, reactive forms can be synchronous.
969-
This makes the controls easier to work with. You have access to
970-
everything - when you update any value, or need to access a
971-
children registered on the parent form, they are available immediately.
972-
973-
To see why this synchronicity matters, a comparison with template
974-
driven forms is helpful. Template driven forms have to be async
975-
because they delegate to directives in the template and must
976-
avoid "changed after checked" errors. As a result, if you have
977-
a template driven form, and you want to manipulate it from
978-
within the component class (for example, make a `ViewChild`
979-
query for `NgForm`), you'll see that on init it has
980-
_no children yet_. They're registered asynchronously, so
981-
you'd have to remember have to check on the next tick.
982-
The same goes for updating the value.
983-
984-
This also affects testing of template-driven forms. You always
985-
have to wrap your test block in `async()` or `fakeAsync()` to
986-
avoid looking for values in the form that aren't available yet.
987-
With reactive forms, everything is available
988-
when you expect it to be.
989-
9901003

9911004
.l-main-section
9921005
:marked

0 commit comments

Comments
 (0)