Angular Reactive form Validations and custom validations

 


Angular is smart and flexible framework to build single page applications, it provides two ways to work with forms, template drive form and Reactive form. Template driven form where we write our validations, controls and groups etc whereas Reactive form is smart and has all features in it by default.

Reactive form provides uses model driven approach while working with forms where you can easily handle inputs and binding. Template driven is smart but we need to write all logic for creating forms, here in reactive forms we get it all in.

I am going to show you how you can use form validation in angular there are many ways to show angular validation error message.

In this section I will demonstrate you how you can apply angular form validation on submit using angular form builder and angular formgroup.We are going to use reactive forms for form validation in angular for that we will use ReactiveFormsModule.

we need to add ReactiveFormsModule from angular form library that is '@angular/forms'.Now we are ready to use angular formGroup and angular form builder in our app. lets create a angular formgroup using angular form builder.

You may find the complete code at bottom of this article

lets import angular formGroup from angular forms library and take a new variable of type angular FormGroup and inject angular FormBuilder in constructor as private.For Angular validation error message we need to let angular validator know those all attributes we got to use in angular validation reactive form.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-custom-validator',
  templateUrl: './custom-validator.component.html',
  styleUrls: ['./custom-validator.component.css']
})
export class CustomValidatorComponent {
  form: FormGroup;
  constructor(private formBuilder: FormBuilder) { }
}

First Name and Last Name:

As we only allow characters in names control we need to define pattern in angular validators under angular formBuilder group
firstName: ['', [Validators.required, Validators.pattern('^[a-zA-Z \-\']+')]]
 
On the Html side we will define our formControlName in the input field so that angular formGroup can know the control added to it and it cna apply angular valdiations
we will add a required attribute to it and now our angular form can work as two way binding and it can get or set values using angular FormGroup.
further, we need to define our angular validation error message for different purpose.
Angular reactive form can have multiple type of validations like required, angular validators pattern, angular validators minlength,angular validator maxlength, angular validators email etc.
Angular form validation on submit will also work to show required fields angular validation error message.

Email Validation

The main purpose of Email validation is to achieve a valid email address , for that angular validator has its own solutions now. we can use Validators.email from angular Validator. we can also use regex pattern at this place using Validators.pattern.
 email: ['', [Validators.required, Validators.email]],
here we can see how it works:
For required angular validation error message we can simply add condition if it is required and touched.
For Valid email we can use Validators.pattern way or Validators.email.
Email should have @ and .com or any other provider.
we used required angular validation error message and one another for invalid email error message where we used angular validaion email. we used required and touched property of angular form controls to trigger the true condition to show the message. Angular form validation on submit will also work to show required fields angular validation error message.

Password and Confirm Password

Main purpose of the Password and confirm password in angular validators is to match exactly same password in both input fields and Angular reactive form provides 
 ngOnInit(): void {
    this.form = this.formBuilder.group({
      password: ['', [Validators.required]],
      confirmPassword: ['', [Validators.required]],
    }, { validators: this.checkPasswords });
  }
  checkPasswords(group: FormGroup) { // here we have the 'passwords' group
    const password = group.get('password').value;
    const confirmPassword = group.get('confirmPassword').value;
  
    return password === confirmPassword ? null : { notSame: true }
  }
a way for it , first i would tell you we need to create a angular custom validator to match them. when we create angular FormGroup using formbuilder we need to pass an option for angular validators that is angular AbstractControlOptions into it as shown below:
we need to create a custom function that accepts angular FormGroup argument and then return us a variable of type Boolean if the password and confirm password Input field are not same.
For both input fields add a required angular validation error message matching two condition if the field is required and it is touched so that the error message would not show when the angular form is untouched.
Angular form validation on submit will also work to show required fields angular validation error message because we are using angular form validators touched property at the same time.

Gender using Radio input fields

We are using two radio input fields those are for male and female here. use angular formControlName same for both fields. 
gender: ['', [Validators.required]]
here we can only show angular validation for required error message.
at the same time if user does not touch any of the field then angular form validation on submit will work.

Phone Number

We can use required , only integer and matching pattern angular validation error message here 
for that we will add an angular validator pattern under angular formbuilder. Now let declare minimum and maximum integer length from angular validators under angular formbuilder.
to show angular validation error message. 
 phoneNumber: ['', [Validators.required, Validators.minLength(11),
 Validators.maxLength(11), Validators.pattern('^[0-9]*$')]]
Angular form validation on submit will also work to show required fields angular validation error message because we are using angular form validators touched property at the same time.

When it all works together it something looks like this.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-custom-validator',
  templateUrl: './custom-validator.component.html',
  styleUrls: ['./custom-validator.component.css']
})
export class CustomValidatorComponent implements OnInit {
  form: FormGroup;
  constructor(private formBuilder: FormBuilder) { }

  ngOnInit(): void {
    this.form = this.formBuilder.group({
      firstName: ['', [Validators.required, Validators.pattern('^[a-zA-Z \-\']+')]],
      lastName: ['', [Validators.required, Validators.pattern('^[a-zA-Z \-\']+')]],
      email: ['', [Validators.required, Validators.email]],
      password: ['', [Validators.required]],
      confirmPassword: ['', [Validators.required]],
      gender: ['', [Validators.required]],
      phoneNumber: ['', [Validators.required, Validators.minLength(11),
      Validators.maxLength(11), Validators.pattern('^[0-9]*$')]]
    }, { validators: this.checkPasswords });
  }
  onSubmit() {
    if (!this.form.valid) {
      this.form.markAllAsTouched();
    } else {
      return true;
    }
  }
  checkPasswords(group: FormGroup) { // here we have the 'passwords' group
    const password = group.get('password').value;
    const confirmPassword = group.get('confirmPassword').value;
  
    return password === confirmPassword ? null : { notSame: true }
  }
}

HTML

<div class="container">
    <div class="row">
        <div class="col text-center">
            <h1 class="font-weight-bold">Angular Validations using Reactive form/ Custom validation</h1>
        </div>
    </div>
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
        <div class="row">
            <div class="col-md-12">
                <div class="form-group">
                    <label>First Name</label>
                    <input required type="text" class="form-control" placeholder="Enter First Name"
                        formControlName='firstName'>
                    <small class="form-text text-danger"
                        *ngIf=" (form.controls['firstName'].errors?.required) && form.controls['firstName'].touched">Please
                        Enter your first Name</small>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['firstName'].errors?.pattern) && form.controls['firstName'].touched">First
                        name should only contain characters</small>
                </div>
                <div class="form-group">
                    <label>Last Name</label>
                    <input required type="text" class="form-control" placeholder="Enter Last Name"
                        formControlName='lastName'>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['lastName'].errors?.required) && form.controls['lastName'].touched">Please
                        Enter your last Name</small>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['lastName'].errors?.pattern) && form.controls['lastName'].touched">Last
                        name should only contain characters</small>
                </div>
                <div class="form-group">
                    <label>Email</label>
                    <input required type="email" class="form-control" placeholder="Enter your email"
                        formControlName='email'>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['email'].errors?.required) && form.controls['email'].touched">Please Enter
                        your email address</small>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['email'].errors?.email) && form.controls['email'].touched">Please Enter a
                        valid email address</small>
                </div>
                <div class="form-group">
                    <label>Password</label>
                    <input required type="password" class="form-control" placeholder="Enter your Password"
                        formControlName='password'>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['password'].errors?.required) && form.controls['password'].touched">Please
                        Enter a password</small>
                </div>
                <div class="form-group">
                    <label>Confirm Password</label>
                    <input required type="password" class="form-control" placeholder="Enter your confirm Password"
                        formControlName='confirmPassword'>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['confirmPassword'].errors?.required) && form.controls['confirmPassword'].touched">Please
                        confirm your password</small>
                    <small class="form-text text-danger"
                        *ngIf="form.hasError('notSame') && form.controls['confirmPassword'].touched">Please match your
                        password</small>
                </div>
                <div class="form-group">
                    <div class="row">
                        <div class="col-md-6">
                            <input required type="radio" class="form-check-input" value="male" name="gender"
                                formControlName="gender">
                            <label class="form-check-label">Male</label>
                        </div>
                        <div class="col-md-6">
                            <input required type="radio" name="gender" value="female" class="form-check-input"
                                formControlName="gender">
                            <label class="form-check-label">Female</label>
                        </div>
                    </div>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['gender'].errors?.required) && form.controls['gender'].touched">Please
                        choose a gender</small>
                </div>
                <div class="form-group">
                    <label>Phone Number</label>
                    <input required type="text" class="form-control" placeholder="Enter your phone number"
                        formControlName="phoneNumber">
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['phoneNumber'].errors?.required) && form.controls['phoneNumber'].touched">Please
                        Enter your phone number</small>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['phoneNumber'].errors?.minlength || form.controls['phoneNumber'].errors?.maxlength) && (form.controls['phoneNumber'].touched && !form.controls['phoneNumber'].errors?.pattern)">Phone
                        number should contain 11 digits</small>
                    <small class="form-text text-danger"
                        *ngIf="(form.controls['phoneNumber'].errors?.pattern) && form.controls['phoneNumber'].touched">Phone
                        number should only contain integers</small>
                </div>
                <div class="row">
                    <div class="col">
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </div>
                </div>
            </div>
        </div>
    </form>
</div>

Summary

In this section, we learned how we can build Angular Reactive Forms and Forms validations with FormBuilder. we learned how we can create custom validation as we did for matching password and confirm passwords. Consider subscribing. Thanks for reading.

No comments:

Powered by Blogger.