Home » Framework » Angular » Template-driven and Reactive forms validation in Angular

Template-driven and Reactive forms validation in Angular

Form validation is the most important part while using template-driven and reactive forms in angular applications. Validations are useful to get the correct information from the user through the forms. Here let us see how to validate template-driven and reactive forms by using the built-in validators of angular.

Before going into the validation part let us see the built-in validators available in angular.

Built-in Validators in Angular Application

Angular provides some set of built-in validators to validate the form controls. Those are min, max, required, requiredTrue, email, minLength, maxLength, and pattern.

min() validator

min() validator validates whether the input value to be greater than or equal to the specified value. Here the input value (or) the form control input should be a number.

max() validator

max() validator validates whether the input value to be less than or equal to the specified value. Here also the input should be a number

required() validator

required() validator validates whether the input value is non-empty or not. Here spaces are also considered as a non-empty input.

requiredTrue() validator

requiredTrue() validator validates whether the input value to be true or not. This is mostly used in checkboxes in a reactive form. In template-driven form, the validator required does the same thing as requiredTrue.

email() validator

email() validator validates the input value to be in the format of email ID. It uses the regular expression pattern to validate the email and this pattern is based on the WHATWG HTML Speciation of the valid email addresses.

minLength() validator

minLength() validator validates the input value that has at least the minimum number of characters based on the specified length. The type of input value should have a numeric length. For example string or array.

If any type of input that has a numeric length is zero (or) any type that doesn't have a numeric length then the minLength() validator doesn't validate the input. Here spaces are considered as value.

maxLength() validator

maxLength() validator validates the input value that has the maximum number of characters at most based on the specified length. This validator has the same behavior as the minLength() validator.

pattern() validator

pattern() validator validates the input value that matches with the regex pattern.

I hope you understood the built-in validators in angular. Now let us use that to validate forms.

Template-Driven form validation using built-in validators in Angular

In a template-driven form, we have to add the validation attributes (or) directives in the form controls input. Here all the validation attributes are used in the HTML template itself. These attributes match with the validation functions to validate the form controls through the angular directives.

For example, the below validator directive math with the corresponding validator function to validate the template-driven form inputs.

Validator directives (Template-driven form)Matched Validator Function
requiredValidators.required
minlengthValidators.minLength()
maxlengthValidators.maxLength()

Like above the all built-in validators match with the corresponding validator functions.

Now let us create the template-driven signup form and use all the built-in validators to validate the form controls input.

app.component.html

<h2>Template-Driven Signup Form with validations</h2>
<form #tdSignupForm="ngForm" (ngSubmit)="tdSignupFormSubmit()" novalidate>
    <div class="signup-form">
    <div class="signup-form-controls">
        <label>First Name</label>
        <input type="text" [(ngModel)]="user.firstName" name="firstName"  #firstName="ngModel" minlength="4" required>
        <div *ngIf="firstName.invalid && (firstName.dirty || firstName.touched)" class="alert">
            <div *ngIf="firstName.errors?.required">
                First Name is required.
            </div>   
            <div *ngIf="firstName.errors?.minlength">
                First Name should be atleast 4 characters
            </div>   
        </div>        
    </div>
   
    <div class="signup-form-controls">
        <label>Last Name</label>
        <input type="text" [(ngModel)]="user.lastName" name="lastName" #lastName="ngModel" maxlength="4" required>
        <div *ngIf="lastName.invalid && (lastName.dirty || lastName.touched)" class="alert">
            <div *ngIf="lastName.errors?.required">
                Last Name is required.
            </div> 
            <div *ngIf="lastName.errors?.maxlength">
                Last Name should be maximum 4 characters
            </div>      
        </div>  
    </div>
    <div class="signup-form-controls">   
        <label>Gender</label>
        <select [(ngModel)]="user.gender" name="gender" #gender="ngModel" required>
            <option value="">--Select--</option>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Transgender">Transgender</option>
       </select>        
        <div *ngIf="gender.invalid && (gender.dirty || gender.touched)" class="alert">
            <div *ngIf="gender.errors?.required">
                Gender is required.
            </div>       
        </div> 
    </div>
    <div class="signup-form-controls">   
        <label>Email</label>
        <input type="text" [(ngModel)]="user.email" name="email" #email="ngModel" required email>
        <div *ngIf="email.invalid && (email.dirty || email.touched)" class="alert">
            <div *ngIf="email.errors?.required">
                Email is required.
            </div>
            <div *ngIf="email.errors?.email">
                Invalid Email Id
            </div>       
        </div> 
    </div>
    <div class="signup-form-controls">   
        <label>Age</label>
        <input type="number" [(ngModel)]="user.age" name="age" #age="ngModel" required min=18 max=35>
        <div *ngIf="age.invalid && (age.dirty || age.touched)" class="alert">
            <div *ngIf="age.errors?.required">
                Age is required (Allowed only Numbers).
            </div>
            <div *ngIf="age.errors?.min">
                Age should 18 to 35
            </div> 
            <div *ngIf="age.errors?.max">
                Age should 18 to 35
            </div>       
        </div> 
    </div>
    <div class="signup-form-controls">   
        <label>Mobile Number</label>
        <input type="text" [(ngModel)]="user.mobile" name="mobile" #mobile="ngModel" required pattern="^[0-9]*$" minlength="10" maxlength="10">
        <div *ngIf="mobile.invalid && (mobile.dirty || mobile.touched)" class="alert">
            <div *ngIf="mobile.errors?.required">
                10 digit Mobile Number is required.
            </div>
            <div *ngIf="mobile.errors?.pattern">
                Invalid Mobile Number
            </div>                   
        </div> 
    </div>
    <div class="signup-form-controls">   
        <label>Terms and Conditions</label>
        <input type="checkbox" [(ngModel)]="user.tc" name="tc" #tc="ngModel"  required>
        <div *ngIf="tc.invalid && (tc.dirty || tc.touched)" class="alert">
            <div *ngIf="tc.errors?.required">
                Tick this box
            </div>                   
        </div> 
    </div>
    <div class="signup-form-controls">
        <button type="submit" [disabled]="!tdSignupForm.valid">Submit</button>
    </div>
    </div>
</form>

app.component.ts

import { Component } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-formvalidation';
  //Template-driven Form Controls
  user = {
    'firstName':'',
    'lastName':'',
    'gender':'',
    'email':'',
    'age':'',
    'tc':false,
    'mobile':''
  }
  tdSignupFormSubmit(){
    console.log(this.user);
  }
}

To use the template-driven form in the angular application we have to import the FormsModule in the app.module.ts file like below.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule} from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Add these CSS styles in the app.component.css file to make the form good-looking.

app.component.css

.alert{
    color:red;
}
.signup-form{
    padding:15px;
}
.signup-form-controls{
    padding-top:20px;
}

Yup!. We have created the template-driven signup form and done the validation through the built-in custom validators. In this form, we have added all the validation attributes in the HTML template itself. You can run the application and see the below form in the browser.

template-driven-signup-form-with-validation
template-driven-signup-form-with-validation

In the above form you can see like #name="ngModel" in all the form controls input. This kind of declaration exports the NgModel into a local variable. This declaration is mandatory for template-driven forms to validate the inputs.

Now let us see the validations used in the form controls one by one below.

  1. The first name text box uses the minLength="4" validator to validate the input that has atleast minimum of 4 characters.

2. The second name text box uses the maxlength="4" validator to validate the input that has a maximum of 4 characters. Here the input text box allows you to enter only the 4 characters

3. The gender dropdown uses the required validator to ensure that the input value is non-empty.

4. The email text box uses the email validator to validate the input to be in the format of email ID.

5. The age input box uses the min=18 and max=35 validator to validate the input value that should be between 18 and 35. Here the type of input should be a number.

6. The mobile number text box uses the pattern="^[0-9]*$" validator to allow only the numbers but not the characters. The additional validators minlength="10" and maxlength="10" ensure that the number should be in 10 digit format.

7. Finally the terms and conditions check box uses the required validator to ensure that the checkbox is checked or not.

After all these validations are successful then you can see the submit button enabled. You can click the submit button to see all the input values of the form in the browser console.

Reactive form validation using built-in validators in Angular

Here let us create the Reactive signup form that has all the inputs as same as the template-driven form that we created above. Here the validators are added in the component classes to validate the form inputs.

There are two types of syntaxes available in angular to configure validators in a component class. For example, if we want to validate the email field in the form with the two validator functions Validators.required and Validators.email then we can use the below two ways of syntaxes.

email: ['', [ Validators.required,Validators.email]]

(or)

email: ['initial value', 
        {
          validators: [Validators.required,Validators.email]
        }
      ],

From the above, we can choose any method we like. Here I have used the first method to validate the below reactive form.

app.component.html

<h2>Reactice Signup Form with validations </h2> 
<form [formGroup]="signupForm" (ngSubmit)="ReSignupFormSubmit()" novalidate>
    <div class="signup-form">
        <div class="signup-form-controls">
            <label>First Name</label>
            <input type="text" formControlName="firstName" name="firstname">
            <div *ngIf="signupForm.controls.firstName.invalid && 
                (signupForm.controls.firstName.dirty || signupForm.controls.firstName.touched)" class="alert">
                <div *ngIf="signupForm.controls.firstName.errors?.required">
                    First Name is required.
                </div>   
                <div *ngIf="signupForm.controls.firstName.errors?.minlength">
                    First Name should be atleast 4 characters
                </div>   
            </div> 
        </div>
        <div class="signup-form-controls">
            <label>Last Name</label>
            <input type="text" formControlName="lastName" name="lastname" >
            <div *ngIf="signupForm.controls.lastName.invalid && 
                (signupForm.controls.lastName.dirty || signupForm.controls.lastName.touched)" class="alert">
                <div *ngIf="signupForm.controls.lastName.errors?.required">
                    Last Name is required.
                </div>   
                <div *ngIf="signupForm.controls.lastName.errors?.maxlength">
                    Last Name should be maximum 4 characters
                </div>   
            </div> 
        </div>
        <div class="signup-form-controls">
            <label>Gender</label>
            <select formControlName="gender" name="gender">
                    <option value="">--Select--</option>
                    <option value="Male">Male</option>
                    <option value="Female">Female</option>
                    <option value="Transgender">Transgender</option>
            </select>            
            <div *ngIf="signupForm.controls.gender.invalid && 
                (signupForm.controls.gender.dirty || signupForm.controls.gender.touched)" class="alert">
                <div *ngIf="signupForm.controls.gender.errors?.required">
                    Gender is required.
                </div>             
            </div> 
        </div>
        <div class="signup-form-controls">   
            <label>Email</label>
                <input type="text" formControlName="email" name="email" >
                <div *ngIf="signupForm.controls.email.invalid && 
                    (signupForm.controls.email.dirty || signupForm.controls.email.touched)" class="alert">
                    <div *ngIf="signupForm.controls.email.errors?.required">
                        Email is required.
                    </div>
                    <div *ngIf="signupForm.controls.email.errors?.email">
                        Invalid Email Id
                    </div>       
                </div> 
        </div>
            <div class="signup-form-controls">   
                <label>Age</label>
                <input type="number" formControlName="age" name="age" >
                <div *ngIf="signupForm.controls.age.invalid && 
                (signupForm.controls.age.dirty || signupForm.controls.age.touched)" class="alert">
                    <div *ngIf="signupForm.controls.age.errors?.required">
                        Age is required (Allowed only Numbers).
                    </div>
                    <div *ngIf="signupForm.controls.age.errors?.min">
                        Age should 18 to 35
                    </div> 
                    <div *ngIf="signupForm.controls.age.errors?.max">
                        Age should 18 to 35
                    </div>       
                </div> 
            </div>
            <div class="signup-form-controls">   
                <label>Mobile Number</label>
                <input type="text" formControlName="mobile" name="mobile" >
                <div *ngIf="signupForm.controls.mobile.invalid && 
                    (signupForm.controls.mobile.dirty || signupForm.controls.mobile.touched)" class="alert">
                    <div *ngIf="signupForm.controls.mobile.errors?.required">
                        10 digit Mobile Number is required.
                    </div>
                    <div *ngIf="signupForm.controls.mobile.errors?.pattern">
                        Invalid Mobile Number
                    </div>                       
                </div> 
            </div>
            <div class="signup-form-controls">   
                <label>Terms and Conditions</label>
                <input type="checkbox" formControlName="tc" name="tc">
                <div *ngIf="signupForm.controls.tc.invalid && 
                    (signupForm.controls.tc.dirty || signupForm.controls.tc.touched)" class="alert">
                    <div *ngIf="signupForm.controls.tc.errors?.required">
                        Tick this box
                    </div>                   
                </div> 
            </div>
        <div class="signup-form-controls">
            <button type="submit" [disabled]="!signupForm.valid">Submit</button>
        </div>
    </div>
  </form>

app.component.ts

import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-formvalidation';
  //Reactive Form Controls
  constructor(private fb: FormBuilder) { }
  signupForm = this.fb.group({
    "firstName": ["", [Validators.required, Validators.minLength(4)]],
    "lastName": ["", [Validators.required, Validators.maxLength(4)]],
    "gender": ["", Validators.required],
    "email": ["", [Validators.required,Validators.email]],
    "age": ["", [Validators.required,Validators.min(18),Validators.max(35)]],
    "mobile": ["", [Validators.required, Validators.pattern("^[0-9]*$"),
              Validators.minLength(10),Validators.maxLength(10)]],
    "tc": [false, Validators.requiredTrue]
  });
  ReSignupFormSubmit(){
    console.log(this.signupForm.value);
  }
}

To use Reactive Form in the angular application we have to import the ReactiveFormsModule in the app.module.ts file like below.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

In the above Reactive Form, we have used the FormBuilder service to generate all the form controls and within that form controls, we used all the built-in validators to validate the form inputs.

The validation of all the form controls is already explained in the template-driven form section. Please refer to the same. You can run the application and see the below reactive form in the browser.

Reactive-signup-form-with-validation
Reactive-signup-form-with-validation

In Reactive form, we can add more logic and validations when compared to template-driven form. So my opinion is reactive form is the right choice to handle the complex logic and validations.

In this article, we have used only the built-validators to validate the form inputs. In the next article let us see how to use the custom validator in both template-driven and reactive forms. Thanks!. Keep Reading!.

Download the full source code from GitHub.

Leave a Reply

Your email address will not be published. Required fields are marked *