Form Validation With Reactive Form In Angular

Reactive forms provide a model-driven approach to handling form inputs whose values change over the time. It is more flexible but more complex scenario, easier to perform an action on value change.

In this article, We will learn ‘Reactive forms validation’. I explain simply step by step forms validation. Follow below steps.

You can create an app by the below command.

npm install -g @angular/cli
ng new reactive-form
cd reactive-form
npm start

Now, open your app.module.ts file and add the below imports there.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,ReactiveFormsModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Open your app.component.html file and add the below form there.

<div class="register-form">
  <h3>Register form</h3>
  <form [formGroup]="registerForm" (ngSubmit)="onSubmit()">
    <div class="form-group">
      <label>Full Name</label>
      <input
        type="text"
        formControlName="fullname"
        class="form-control"
        [ngClass]="{ 'is-invalid': submitted && f.fullname.errors }"
      />
      <div *ngIf="submitted && f.fullname.errors" class="invalid-feedback">
        <div *ngIf="f.fullname.errors.required">Fullname is required</div>
      </div>
    </div>

    <div class="form-group">
      <label>Username</label>
      <input
        type="text"
        formControlName="username"
        class="form-control"
        [ngClass]="{ 'is-invalid': submitted && f.username.errors }"
      />
      <div *ngIf="submitted && f.username.errors" class="invalid-feedback">
        <div *ngIf="f.username.errors.required">Username is required</div>
        <div *ngIf="f.username.errors.minlength">
          Username must be at least 6 characters
        </div>
        <div *ngIf="f.username.errors.maxlength">
          Username must not exceed 20 characters
        </div>
      </div>
    </div>

    <div class="form-group">
      <label>Email</label>
      <input
        type="text"
        formControlName="email"
        class="form-control"
        [ngClass]="{ 'is-invalid': submitted && f.email.errors }"
      />
      <div *ngIf="submitted && f.email.errors" class="invalid-feedback">
        <div *ngIf="f.email.errors.required">Email is required</div>
        <div *ngIf="f.email.errors.email">Email is invalid</div>
      </div>
    </div>

    <div class="form-group">
      <label>Password</label>
      <input
        type="password"
        formControlName="password"
        class="form-control"
        [ngClass]="{ 'is-invalid': submitted && f.password.errors }"
      />
      <div *ngIf="submitted && f.password.errors" class="invalid-feedback">
        <div *ngIf="f.password.errors.required">Password is required</div>
        <div *ngIf="f.password.errors.minlength">
          Password must be at least 6 characters
        </div>
        <div *ngIf="f.password.errors.maxlength">
          Username must not exceed 40 characters
        </div>
      </div>
    </div>

    <div class="form-group">
      <label>Confirm Password</label>
      <input
        type="password"
        formControlName="confirmPassword"
        class="form-control"
        [ngClass]="{ 'is-invalid': submitted && f.confirmPassword.errors }"
      />
      <div *ngIf="submitted && f.confirmPassword.errors" class="invalid-feedback">
        <div *ngIf="f.confirmPassword.errors.required">
          Confirm Password is required
        </div>
        <div *ngIf="f.confirmPassword.errors.mustMatch">
          Confirm Password does not match
        </div>
      </div>
    </div>

    <div class="form-group form-check">
      <input
        type="checkbox"
        formControlName="acceptTerms"
        class="form-check-input"
        [ngClass]="{ 'is-invalid': submitted && f.acceptTerms.errors }"
      />
      <label for="acceptTerms" class="form-check-label"
        >I have read and agree to the Terms</label>
      <div *ngIf="submitted && f.acceptTerms.errors" class="invalid-feedback">
        Accept Terms is required
      </div>
    </div>

    <div class="form-button">
      <button type="submit" class="btn-primary">Register</button>
      <button type="button" (click)="onReset()" class="btn-warning">Reset</button>
    </div>
  </form>
</div>

Open your app.component.ts file and add the below code there.

import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MustMatch } from './confirmed.validator';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'reactive-form';
  registerForm: FormGroup;
  submitted = false;
  constructor(private formBuilder: FormBuilder) {
    this.registerForm = this.formBuilder.group(
      {
        fullname: ['', Validators.required],
        username: [
          '',
          [
            Validators.required,
            Validators.minLength(6),
            Validators.maxLength(20)
          ]
        ],
        email: ['', [Validators.required, Validators.email]],
        password: [
          '',
          [
            Validators.required,
            Validators.minLength(6),
            Validators.maxLength(40)
          ]
        ],
        confirmPassword: ['', Validators.required],
        acceptTerms: [false, Validators.requiredTrue]
      },
      {
        validator: MustMatch('password', 'confirmPassword')
      }
    );
  }
  ngOnInit(): void {
  }

  get f(): { [key: string]: AbstractControl } {
    return this.registerForm.controls;
  }

  onSubmit(): void {
    this.submitted = true;

    if (this.registerForm.invalid) {
      return;
    }

    console.log(JSON.stringify(this.registerForm.value, null, 2));
  }

  onReset(): void {
    this.submitted = false;
    this.registerForm.reset();
  }
}

Create confirmed.validator.ts file in app folder for password validation and add the below code there

import { FormGroup } from '@angular/forms';

export function MustMatch(controlName: string, matchingControlName: string) {
    return (formGroup: FormGroup) => {
        const control = formGroup.controls[controlName];
        const matchingControl = formGroup.controls[matchingControlName];

        if (matchingControl.errors && !matchingControl.errors.mustMatch) {            
            return;
        }
        if (control.value !== matchingControl.value) {
            matchingControl.setErrors({ mustMatch: true });
        } else {
            matchingControl.setErrors(null);
        }
    }
}

Now, add some basic css in app.component.css file

body{
    margin: 0;    
    font-size: 14px;
    font-family: monospace;
}
.register-form {
    max-width: 450px;
    margin: 0 auto;    
    font-family: Arial, Helvetica, sans-serif;
    font-size: 14px;
}
h3{
    text-align: center;
    font-size: 22px;
}
label{
    font-weight: 600;
    opacity: .7;
    margin-bottom: 5px;
    display: inline-block;
}
.form-group{
    margin-bottom: 15px;
}
.form-control{
    width: 427px;
    display: block;
    border: 1px solid #ddd;
    border-radius: 5px;
    padding: 10px;
}
.form-button{
    display: flex;
    justify-content: space-between;
}
.form-button button{
    width: 100px;
    height: 40px;
    border: 1px solid #ddd;
    background-color: #fff;
    color: #000;
    transition: all .3s;
}
.form-button button.btn-primary{background-color: #5151fd;color: #fff;}
.form-button button.btn-warning{background-color: #ef551a;color: #000;}
.form-button button:hover{
    cursor: pointer;
    background-color: #000;
    color: #fff;
    border-color: #000;
}
.invalid-feedback{font-size: 12px;color: #ff0000;}

That’s it! now check your output

Submit a Comment

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

Footer Logo

Subscribe

Select Categories