Note: Since writing this article, we no longer recommend explicit FormGroup or FormControl use.
See theses articles instead
Angular's built-in Form Validation engine saves a ton of time when writing your own form validators.
It's simple to understand and works well. But we as developers have to think about things a little differently.
What's a FormGroup?
<form [formGroup]="formGroup">
A formGroup is an Angular directive.
The code above is assigning "formGroup" to the [formGroup] directive. This is called 'a binding'.
Note: The form element doesn't have to exist in the HTML it can just be created in our code.
FormGroup bindings are indirect bindings to the elements. Traditional Angular bindings are direct element bindings.
A FormGroup Aggregates FormControls
<form [formGroup]="formGroup">
<div class="Info" *ngIf="person.isEdit">
<label>First Name</label>
<input formControlName="firstName"
id="personFirstName"
placeholder="Enter First Name here"
type ="text">
</div>
...
The input element above, has a formControlName. It is assigned the name "firstName" which will be contained in the formGroup in our code.
Notice; however, that there is no direct binding to a "Person" object done here. It's done in the Javascript code. The formControl also uses indirect binding techniques.
The Typescript Bindings
The new formGroup must be created at ngInit time as show below. This is where we see the actual property bindings to the person object.
private formGroupBind() {
let namePattern =
/^(?=.{1,40}$)[a-zA-Z]+(?:[-'\s][a-zA-Z]+)*$/;
this.formGroup = new FormGroup({
// The lastName key is the Form control Name
lastName: new FormControl(
//Property binding
this.person.lastName, [
//One of more actions to perform
Validators.required,
Validators.pattern(namePattern),
]),
... repeat pattern above for all formcontrols
this.formGroup.enable;
}
// The person class
export class Person {
firstName: string = "";
lastName: string = "";
middleName: string = "";
...
Each FormControl is an object, where the key is used in the HTML. It Binds that partiular element with that particular formControl.
The heart of the indirection is that the key of the formControl is used as the formControlName, and the specif person field is bound here.
Quite different from traditional binding.
// Instead of a name for this element, we assign a formControlName
<input formControlName="firstName"
Each formControl can specify one or more validation rules like this:
firstName: new FormControl(
this.person.firstName, [
Validators.required,
Validators.pattern(
namePattern),
]),
Here we are saying that the firstName formControl requires validation and the pattern is a regex statement in the variable namePattern.
// using a regex pattern, this is the validation of the content
let namePattern =
/^(?=.{1,40}$)[a-zA-Z]+(?:[-'\s][a-zA-Z]+)*$/;
/^(?=.{1,40}$)[a-zA-Z]+(?:[-'\s][a-zA-Z]+)*$/;
- ^ start a first of the line
- (?=.{1,40}$) Non Capture Group of any char from 1 to 40 chars in length -[a-zA-Z]+ These characters are allowed, one or more matches -(?:[-'\s][a-zA-Z]+) Non Capture Group, can have other characters followed by alphabet. 1 or more times -* any other context -$ up to end of line
When the user inputs invalid values, Angular will mark that element's background color to a red tint. It stays that way until it's correct. Before we save anything we check the validity via the
formGroup.isValid property
Thinking Differently
When we decide to use FormControls we need to use that interface to get/set values and determine validation. We don't usually set values at the DOM layer any longer, and we don't rely on NGModel; as all the binding is done with the FormControlGroup (the container of all the formControls).
Here's an example of checking all formControls within a formGroup for validity.
if(formGroup.Valid){
//save to back end...
}
FormControls, are too nice to ignore when validation is a primary concern.
JWP2020
Top comments (0)