Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add forms overview guide #25663

Closed
wants to merge 18 commits into from

Conversation

brandonroberts
Copy link
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

[ ] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[x] Documentation content changes
[ ] angular.io application / infrastructure changes
[ ] Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

[ ] Yes
[x] No

Other information

Adds Forms Overview page to Forms section. Reorganizes forms guides in nav also.

@brandonroberts brandonroberts added comp: docs action: review The PR is still awaiting reviews from at least one requested reviewer area: forms target: patch This PR is targeted for the next patch release labels Aug 24, 2018
@mary-poppins
Copy link

You can preview e22d60a at https://pr25663-e22d60a.ngbuilds.io/.


## 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its -> it's?


```typescript
@Component({
template: `Name: <input type="text" [formControl]="name"/> `
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current convention in doc seems to be <input> rather than <input/>. (Another case below)


Let’s look at how the data flows for an input with reactive forms.

**Diagram of Input Event flow For Reactive Forms**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flow For -> Flow for? (Another case below)

template: `Name: <input type="text" [(ngModel)]="name"/>`
})
export class TemplateNameComponent {
name = ‘’;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the ASCII quote.


**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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NgModel should be in backticks?

@mary-poppins
Copy link

You can preview 0388215 at https://pr25663-0388215.ngbuilds.io/.

Angular forms allow you to:

* Capture the current value and validation status of a form
* Track and listen changes to the form's data model
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listen for changes
...also, I believe Google style calls for periods on list items


* **Reactive** using existing instances of a `FormControl` or `FormGroup` to build a form model. This form
model is synced with form input elements through directives to track and communicate changes back to the form model. Changes
to the value and status of the controls as provided as observables.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are provided


You can build forms in one of two ways:

* **Reactive** using existing instances of a `FormControl` or `FormGroup` to build a form model. This form
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reactive forms use ...
(bold doesn't render properly)

* **Reactive** using existing instances of a `FormControl` or `FormGroup` to build a form model. This form
model is synced with form input elements through directives to track and communicate changes back to the form model. Changes
to the value and status of the controls as provided as observables.
* **Template-driven** using directives such as `NgModel` and `NgModelGroup` that provide two-way data binding to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template-driven forms use ...

Copy link
Contributor

@jbogarthyde jbogarthyde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Started copy edit, but too awkward in git. Leaving it for Sarah - just reading it now.

# 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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make parallel:
...to log in, to update a profile, to enter sensitive information, and to perform many other...

@mary-poppins
Copy link

You can preview b819bf6 at https://pr25663-b819bf6.ngbuilds.io/.

Copy link
Contributor

@kara kara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great. Some comments below. I think it will be a bit easier to review once the diagrams are in.


Handling user input with forms is the cornerstone of many common applications. You use forms to log in, to update a profile, to enter sensitive information, and to perform 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 you’re using reactive or template driven forms, these concepts are key to understanding the mechanisms underneath each solution.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: capitalization should be consistent

...input through forms: reactive and template-driven.

Nit: hyphenation should be consistent

Whether you're using reactive or template-driven forms, these...

Nit: I think we can remove the second-to-last sentence and not lose any of the meaning.

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: missing an "a"

If you have a very simple form with...

Also thinking we should clarify "static data", so people don't think we mean a form where "values don't change" (which isn't really a form anymore) or "controls aren't being added/removed" (this is fine in TD forms as long as you use ngIf). I think we mean something like "with basic logic that can be managed solely in the template" - because it gets confusing handling template-driven directives in the component class.

Also do we want to mention data flow somewhere here? If you are using reactive patterns, you probably don't want to use template-driven. Or maybe this is too early? What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its ok to mention here as a quick decision point. I updated the text to be:

  • Reactive forms are more robust: they are more scalable, reusable, and testable. If forms are a key part of your application, or you're already using reactive patterns for building your application, use reactive 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the three main building blocks here should be FormControl, FormGroup, and FormArray (with a sentence describing FormArray too). Value accessors are common to both modules but I wouldn't put them in the same list.

...share underlying building blocks: the FormControl, FormGroup, and FormArray.

Maybe we can remove the section head for value accessors below and discuss them in the next paragraph?


## 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.
Copy link
Contributor

@kara kara Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: enabling/disabling isn't a callback

reading from and writing values to them, disabling or enabling their elements, and providing callback functions for when the control's value changes in the UI or it becomes touched.

We probably shouldn't call out DefaultValueAccessor as attached to every input element since it only applies to text fields that don't have custom value accessors defined. Maybe change to:

A built-in value accessor is attached to every form field when using either forms modules in Angular (example: DefaultValueAccessor), unless a custom value accessor has been activated on that field.


## Forms data flows

When building forms in Angular, it's 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... it's important to understand how the framework handles data flowing from the user or from programmatic changes.

}
```

**Diagram of Input Event Flow For Reactive Forms**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagram?


**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.
Copy link
Contributor

@kara kara Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In template-driven forms, the source of truth is the template, so developers create their desired form through the placement of template-driven directives like NgModel and NgModelGroup. The directives then create the FormControl or FormGroup instances that make up the form model, link them with form elements through a value accessor, and manage them within the constraints of the template's change detection cycle.

This abstraction promotes simplicity over structure. It is less explicit, but you no longer have direct control over the form model. It is simple to add directives, but because these directives are dependent on the UI, they must work around the change detection cycle. Programmatic value changes are registered during change detection (as they occur through an @Input to a directive), so it's not possible to update the value and validity immediately because it may affect elements that have already been checked in that view (e.g. the parent form). For this reason, value changes are delayed until the next tick, which allows change detection to complete and a new change detection process to be triggered with the updated value. In other words, the process happens asynchronously 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 you’re 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With reactive forms, custom validators are functions that receive a control to value to validate.


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.
Copy link
Contributor

@kara kara Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove the part about ViewChild because I'd rather not encourage that:

In order to access the underlying controls with template-driven forms, you must wait for the appropriate lifecycle hooks to finish before extracting any values, testing its validity or changing its value.

I think the testing section might benefit from an example comparing a simple test.

</td>

<td>
Immutable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm can you explain what you mean by mutable in TD?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a section above scalability

Mutability

How changes are tracked plays a role in the efficiency of your application. Reactive forms keep the data model pure by providing it as an immutable data structure. Each time the a change is triggered on the data model, a new data model is returned rather than updating the data model directly. This is more efficient, giving you the ability track unique changes to the data model. It also follows reactive patterns that integrate with observable operators to map and transform data. Template-driven forms rely on mutability with two-way data binding to update the data model in the component as changes are made in the template.

@mary-poppins
Copy link

You can preview 0d05573 at https://pr25663-0d05573.ngbuilds.io/.

aio/content/guide/forms-overview.md Outdated Show resolved Hide resolved
packages/forms/PACKAGE.md Outdated Show resolved Hide resolved
@mary-poppins
Copy link

You can preview 210d1e3 at https://pr25663-210d1e3.ngbuilds.io/.


**Diagram of Input Event Flow For Reactive Forms**

### Data flow in template-driven forms
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this header is too high? It comes before the reactive forms explanation.

@mary-poppins
Copy link

You can preview 8542715 at https://pr25663-8542715.ngbuilds.io/.

kara pushed a commit that referenced this pull request Sep 26, 2018
kara pushed a commit that referenced this pull request Sep 26, 2018
kara pushed a commit that referenced this pull request Sep 26, 2018
kara pushed a commit that referenced this pull request Sep 26, 2018
kara pushed a commit that referenced this pull request Sep 26, 2018
kara pushed a commit that referenced this pull request Sep 26, 2018
kara pushed a commit that referenced this pull request Sep 26, 2018
kara pushed a commit that referenced this pull request Sep 26, 2018
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
FrederikSchlemmer pushed a commit to FrederikSchlemmer/angular that referenced this pull request Jan 3, 2019
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 14, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker aio: preview area: forms cla: yes target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants