Angular (aka Angular2) gives us two ways to create forms:
template driven and model driven (aka reactive). The model driven approach
provides several advantages:
- They are more testable
- They are more dynamic
- Forms can be built at runtime “on the fly” without changing the application code
- They are easier to maintain
- All the logic is in one place
Reactive/model-driven forms do not use Angular directives
such as “ngModel”, “required”, “disabled” etc. Instead of relying on the Angular
framework to power things for us, we use the underlying APIs instead. Instead
of binding Object models to directives like template-driven forms, we declare
and create our own instances inside a component class and construct our own JavaScript
models. This has much more power and is extremely productive to work with as it
allows us to write testable, easier to understand code that keeps all logic in
the same place instead of scattering it around different form templates.
Importing the ReactiveFormsModule
The first step is to import the ReactiveFormsModule (as
opposed to the standard FormsModule) into the module that will contain your
model-driven form. e.g.
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports:
[BrowserModule, ReactiveFormsModule….
FormControl
Each element on the form is mapped to an instance of the
FormControl class. It tracks the value and validation status as well as
offering a set of API methods for accessing the form data.
The declaration of a FormControl class takes as parameters
(in this order):
- Initial value & state (e.g. disabled)
- Any synchronous validator, or array of sync validators
- Any asynchronous validator, or array of async validators
See the API documentation for more details: https://angular.io/docs/ts/latest/api/forms/index/FormControl-class.html
Here is an example declaration:
zipCode: FormControl;
zipCode = new FormControl({value: '', disabled: false}, validators.required);
This code declares a variable of type FormControl, then
assigns it to a new instance of the FormControl class which has an initial
empty value of and is not disabled. It also has a sync validator of “required”.
FormGroup
A FormGroup is just that – a grouping of FormControl
instances. At the highest level it represents the form itself, but FormGroups
can be nested to represent sub-groupings that can make the form easier to
manage. Other advantages are:
- Allows validation at a FormGroup level. E.g. the “submit” button could be enabled/disabled based on the valid status of the FormGroup, which in turn would depend on the valid status of the FormControls in the FormGroup. It would also allow us to implement custom validation
- FormGroup provides a convenient way to declare many controls at once. An array of FormControls can be constructed, e.g. from reference data or a backend service, then passed into the constructor of the FormGroup
Example declaration:
const form = new FormGroup({
firstName: new FormControl(‘Tim’,
Validators.minLength(2)),
lastName: new FormControl('Hodkinson'),
});
console.log(form.value); // {firstName: 'Tim', lastName; 'Hodkinson'}
console.log(form.status); // 'VALID'
Binding to the template
The final step is to bind the code to the html template. We
do this using the Angular [formGroup] directive to bind an html form on the template to the FormGroup. We can then use the
formControlName directive to bind individual FormControls in the FormGroup to the html form
control elements using the name key. For example:
In the code above [formGroup] binds the html form to the
FormGroup we declared in the last section, which we called “form”. The inputs
are then bound to the firstName and lastName FormControls in the “form”
FormGroup.
No comments:
Post a Comment