DEV Community

John Peters
John Peters

Posted on • Edited on

Angular Form Control Validation Patterns

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">
Enter fullscreen mode Exit fullscreen mode

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>
...
Enter fullscreen mode Exit fullscreen mode

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 = "";
...
Enter fullscreen mode Exit fullscreen mode

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"  
Enter fullscreen mode Exit fullscreen mode

Each formControl can specify one or more validation rules like this:

firstName: new FormControl(
  this.person.firstName, [

   Validators.required,
   Validators.pattern(
      namePattern),
  ]),
Enter fullscreen mode Exit fullscreen mode

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]+)*$/;
Enter fullscreen mode Exit fullscreen mode

/^(?=.{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...
}
Enter fullscreen mode Exit fullscreen mode

FormControls, are too nice to ignore when validation is a primary concern.

JWP2020

Oldest comments (0)