docs: add forms overview guide (#25663)

PR Close #25663
This commit is contained in:
Brandon Roberts 2018-08-24 11:12:34 -05:00 committed by Kara Erickson
parent c7e2930f25
commit 129f69c3bc
3 changed files with 247 additions and 52 deletions

View File

@ -0,0 +1,235 @@
# Forms in Angular
Handling user input with forms is the cornerstone of many common applications. You use forms to log in to a page, updating a profile, entering sensitive information, and many other data-entry tasks.
Angular provides two different approaches to handling user input through forms: Reactive and template-driven. Each set of forms promote a distinct way of processing forms and offers different advantages. The sections below provide a comparison of the two approaches and when each one is applicable. There are many different factors that influence your decision on which approach works best for your situation. Whether youre using reactive or template driven forms, these concepts are key to understanding the mechanisms underneath each solution.
In general:
* **Reactive forms** are more robust: they are more scalable, reusable, and testable. If forms are a key part of your application, use reactive forms.
* **Template-driven forms** are useful for adding a simple form to an app, such as a single email list signup form. They are easy to add to an app, but they do not scale as well as reactive forms. If you have very simple form with only static data, use template-driven forms.
## A common foundation
Both reactive and template-driven forms share underlying building blocks, the `FormControl`, `FormGroup` and the `ControlValueAccessor` interface. A `FormControl` instance tracks the value and validation status of an individual form control element. A `FormGroup` instance tracks the same values and statuses for a collection of form controls. How these control instances are created and managed with reactive and template-driven forms will be discussed later in this guide.
## Control value accessors
Control value accessors define a bridge between Angular forms and native DOM elements. The `ControlValueAccessor` interface defines methods for interacting with native elements including: reading from and writing values to them, providing callback functions to listen for value changes, when they are touched, and or enabled or disabled. A [default control value accessor](api/forms/DefaultValueAccessor) is attached to every input element when using either forms modules in Angular.
## Forms data flows
When building forms in Angular, its important to be able understand how the the framework handles data flows from user input to the form and changes from code. Reactive and template-driven follow two different strategies when handling these scenarios. Using a simple component with a single input field, we can illustrate how changes are handled.
Here is a component with an input field for a single control using reactive forms.
```typescript
@Component({
template: `Name: <input type="text" [formControl]="name"/> `
})
export class ReactiveNameComponent {
name = new FormControl();
}
```
Lets look at how the data flows for an input with reactive forms.
**Diagram of Input Event flow For Reactive Forms**
When text is entered into the input field, the control is immediately updated to the new value, which then emits a new value through an observable. The source of truth, the form model, is explicitly defined with the form control in the component class. This model is created independently of the UI and is used to provide the value and validation status for the control instance. Reactive forms use directives to link existing form control instances to form elements in the view. This is important because you have full control over the form model without ever rendering the UI. The source of truth is always correct, because it is synchronously updated at the time changes are made.
Now lets look at the same data flows with template-driven forms.
```typescript
@Component({
template: `Name: <input type="text" [(ngModel)]="name"/>`
})
export class TemplateNameComponent {
name = ;
}
```
**Diagram of Input Event flow For Reactive Forms**
Template-driven forms are less explicit in that the source of truth for is the directives in the template. Directives are necessary to bind the model to the component class. You no longer have direct control of the form model. Template-driven forms use directives such as NgModel and NgModelGroup to create the form control or group instances and manage their lifecycle within the change detection cycle. This abstraction promotes simplicity over structure. Because template-driven forms are dependent on the UI, the change detection process must complete its cycle where it checks for values changes, queues a task for the value to be updated, and performs a tick before the source of truth is correct. The process happens asynchronously to prevent errors from occuring with values changing during the change detection cycle and introduces unpredictability for querying the source of truth.
## Custom validation and testing
Validation is an integral part of managing any set of forms. Whether youre checking for required fields or querying an external API for an existing username, Angular provides a set of built-in validators as well as the ability to create custom validators. With reactive forms, creating custom validators are achieved functions that receives control to validate and returns a result immediately. Because template-driven forms are tied to directives, custom validator directives must be created to wrap a validator function in order to use it in a template.
For more on form validation, visit the [Form Validation](guide/form-validation) guide.
Testing also plays a large part in complex applications and an easier testing strategy is always welcomed. Reactive forms provide an easy testing strategy to due to synchronous access to the form and data models, where controls and data can be queried and manipulated easily through the control without rendering a view. Template-driven forms are asynchronous, which complicates complex testing scenarios. It involves more detailed knowledge of the change detection process and how directives run on each cycle to ensure elements can be queried at the correct time. In order to access the underlying controls with template-driven forms, you must use `ViewChild` to access the `NgForm` and wait for the appropiate lifecycle hooks to finish before extracting any values, testing its validity or changing its value.
## Scalability
If forms are a central part of your application, scalability is very important. Being able to reuse form models across components and data access is critical. Reactive forms makes creating large scale forms easier by providing access to low-level APIs and synchronous access to the data model. Because template-driven forms focus on simplicity and simple scenarios with static content and little validation, they are not as reusable and abstract away the low-level APIs and access to the data model is handled asynchronously.
## Key differences
The table below summarizes the key differences in reactive and template driven forms.
<style>
td, th {vertical-align: top}
</style>
<table>
<tr>
<th>
</th>
<th>
Reactive
</th>
<th width="40%">
Template-Driven
</th>
</tr>
<tr>
<td>
Setup
</td>
<td>
More Explicit
</td>
<td>
Less Explicit
</td>
</tr>
<tr>
<td>
Source of truth
</td>
<td>
The form model
</td>
<td>
The directives in the template
</td>
</tr>
<tr>
<td>
Form Model creation
</td>
<td>
Class
</td>
<td>
Form Directives
</td>
</tr>
<tr>
<td>
Predictability
</td>
<td>
Synchronous
</td>
<td>
Asynchronous
</td>
</tr>
<tr>
<td>
Consistency
</td>
<td>
Immutable
</td>
<td>
Mutable
</td>
</tr>
<tr>
<td>
Data model
</td>
<td>
Structured
</td>
<td>
Unstructured
</td>
</tr>
<tr>
<td>
Custom Validators
</td>
<td>
Functions
</td>
<td>
Directives
</td>
</tr>
<tr>
<td>
Scalability
</td>
<td>
Low-level API access
</td>
<td>
Abstraction on top of APIs
</td>
</tr>
</table>
## Next Steps
After you understand the two approaches to handling form inputs, you can learn more about common examples and practices using reactive forms or template-driven forms. The following guides are the next steps in the learning process for each approach.
* [Reactive Forms](guide/reactive-forms)
* [Form Validation](guide/form-validation#reactive-form-validation)
* [Dynamic forms](guide/dynamic-form)
* [Template-driven Forms](guide/forms)
* [Form Validation](guide/form-validation#template-driven-validation)

View File

@ -16,7 +16,7 @@ Reactive forms use an explicit and immutable approach to managing the state of a
Reactive forms also provide a straightforward path to testing because you are assured that your data is consistent and predictable when requested. Any consumers of the streams have access to manipulate that data safely.
Reactive forms differ from template-driven forms in distinct ways. Reactive forms provide more predictability with synchronous access to the data model, immutability with observable operators, and change tracking through observable streams. If you prefer direct access to modify data in your template, template-driven forms are less explicit because they rely on directives embedded in the template, along with mutable data to track changes asynchronously. See the [Appendix](#appendix) for detailed comparisons between the two paradigms.
Reactive forms differ from template-driven forms in distinct ways. Reactive forms provide more predictability with synchronous access to the data model, immutability with observable operators, and change tracking through observable streams. If you prefer direct access to modify data in your template, template-driven forms are less explicit because they rely on directives embedded in the template, along with mutable data to track changes asynchronously. See the [Forms Overview](guide/forms-overview) for detailed comparisons between the two paradigms.
## Getting started
@ -645,48 +645,3 @@ Listed below are the base classes and services used to create and manage form co
</tr>
</table>
### Comparison to template-driven forms
*Template-driven* forms, introduced in the [Template-driven forms guide](guide/forms), take a completely different approach compared to reactive forms. With template-drive forms, you follow these rules:
* Place HTML form controls (such as `<input>` and `<select>`) in the component template and bind them to data model properties in the component, using directives such as `ngModel`.
* Don't create Angular form control objects. Angular directives create them for you, using the information in your data bindings.
* Don't push and pull data values. Angular handles that for you with `ngModel`. Angular updates the mutable data model with user changes as they happen.
While using template-driven forms means less code in the component class,
they are [asynchronous](guide/reactive-forms#async-vs-sync "Async vs sync"),
which can complicate development in more advanced scenarios.
{@a async-vs-sync}
### Async vs. sync
Reactive forms are synchronous, and template-driven forms are asynchronous.
In reactive forms, you create the entire form control tree in code.
You can immediately update a value or drill down through the descendants of the parent form
because all controls are always available.
Template-driven forms delegate the creation of their form controls to directives.
To avoid *changed after checked* errors,
these directives take more than one cycle to build the entire control tree.
That means you must wait until the next change detection cycle happens before manipulating any of the controls
from within the component class.
For example, if you inject the form control with a `@ViewChild(NgForm)` query and examine it in the
[`ngAfterViewInit` lifecycle hook](guide/lifecycle-hooks#afterview "Lifecycle hooks guide: AfterView"),
you'll discover that it has no children.
You must trigger a change detection cycle using `setTimeout()` before you can
extract a value from a control, test its validity, or set it to a new value.
The asynchrony of template-driven forms also complicates unit testing.
You must wrap your test block in `async()` or `fakeAsync()` to
avoid looking for values in the form that aren't there yet.
With reactive forms, everything is available immediately.

View File

@ -210,26 +210,31 @@
"title": "Forms",
"tooltip": "Angular Forms",
"children": [
{
"url": "guide/forms-overview",
"title": "Forms Overview",
"tooltip": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors."
},
{
"url": "guide/user-input",
"title": "User Input",
"tooltip": "User input triggers DOM events. We listen to those events with event bindings that funnel updated values back into our components and models."
},
{
"url": "guide/reactive-forms",
"title": "Reactive Forms",
"tooltip": "Create a reactive form using FormBuilder, groups, and arrays."
},
{
"url": "guide/forms",
"title": "Template-driven Forms",
"tooltip": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors."
"tooltip": "Create a template-driven form using directives and Angular template syntax"
},
{
"url": "guide/form-validation",
"title": "Form Validation",
"tooltip": "Validate user's form entries."
},
{
"url": "guide/reactive-forms",
"title": "Reactive Forms",
"tooltip": "Create a reactive form using FormBuilder, groups, and arrays."
},
{
"url": "guide/dynamic-form",
"title": "Dynamic forms",