Angular Reactive Form

In previous we have learned, the template drives forms, in a template-driven from where most of our logic, validation, controls are in template or HTML form. We are applying ngModel and other an Angular directive in template and template drive form is suitable for building the simple form with basic validation(required, minlength, maxlength).

Whereas in case of modal driven (Reactive form):  forms, all the control and logic validation of form are defined in your component typescript file. With the model-driven approach, we create form from the instance of FormGroup and the FormBuilder instance allows us to specify form controls and the various validations on the input element of the form in the component. The model drive form is the best choice for creating a complex form, it provides the developer with more control on the form.

In this example, we are learning

  1. How to build a reactive form with custom validation
  2. Apply select form element value from external sources.
  3. Displaying custom error message for each form element error related to validation.

We will make simple reactive form example, we have to follow these step to complete our task.

Step 1: Define reactiveForm module in app.module.ts file

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

imports: [
   ReactiveFormsModule
],

Step 2: Define Form validation in app.component.ts

We will define the form model on from an instance of FormGroup and we will uses form validation from FormBuilder instance. We have to import FormGroup and FormBuilder provider from ‘@angular/form’.

We are defining separate error message for each element validation by define property element in the component and assigning the error message through method called initializeErrorMessages.  Add the following code in app.component.ts file.

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { TamoDepartment } from './model/department.interface';
import { MockDepartment } from './data/mockDepartment';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit{
  public title: string  = 'Angular Reactive Form';
  public formTamo : FormGroup;

  departments: any[];
  titleErrorMessage: string;
  descriptionErrorMessage : string;
  categoryErrorMessage: string;

  constructor(private formBuilder: FormBuilder){
    this.displayDepartments();
  }

  ngOnInit(){
    this.formTamo = this.formBuilder.group({
      "title": [null, Validators.required],
      "description": [null, [Validators.required, Validators.minLength(10), Validators.maxLength(50)]],
      "category" : [null]
    })
  }

  displayDepartments(){
    this.departments = MockDepartment;
    this.initializeErrorMessages();
  }
  
  initializeErrorMessages(){
    this.titleErrorMessage = "This is required";
    this.descriptionErrorMessage ="Description should be of minimum 10 and maximun 50 characters";
    this.categoryErrorMessage = "Category is required";
  }
}

We can assign the value of the form select element department option value from the external data in file app/data /mockDepartment.ts

app/model/department.interface.ts

export interface TamoDepartment{
    id:number,
    name: string,
    description: string
}

In app/data/mockDepartment.ts we have to define the list of department name to array element TamoDepartment[]

import { TamoDepartment } from '../model/department.interface';

export const MockDepartment : TamoDepartment[] = [
    {
        id: 0,
        name: 'Designing',
        description: 'Photoshop, Indesign'
    },
    {
        id: 1,
        name: 'Web Developer',
        description: 'Web through Node and Angular'
    },
    {
        id: 3,
        name: 'Hybrid App Developer',
        description: 'Through Ionic'
    },
    {
        id: 3,
        name: 'Android Developer',
        description: 'The 140 Android App developed'
    },   
    {
        id: 4,
        name: 'IOS Developer',
        description: 'Lastest ISO'
    }
]

 

Step 3:  Define form in app.component.html

Note: We have to assign form name (formTamo) to an Angular directive [fromGroup] and we are also assigning department select element list value from external data.

<div class="container">
  <h1> {{title}} </h1>
  <div class="card">  
    <div class="card-block">
      <form [formGroup]="formTamo" (ngSubmit)="submitDetails(formTamo.value)">
        <div class="form-group">
          <label>Title :</label> 
          <input type="text" class="form-control" formControlName="title" />
          <div class="alert alert-danger" *ngIf="!formTamo.controls['title'].valid && formTamo.controls['title'].touched" >
            {{ titleErrorMessage }}
          </div>
        </div>

        <div class="form-group">
          <label>Description :</label> 
          <textarea class="form-control" formControlName="description"></textarea>
          <div class="alert alert-danger" 
            *ngIf="!formTamo.controls['description'].valid && formTamo.controls['description'].touched" >
              {{ descriptionErrorMessage  }}
            </div>
        </div>

        <div class="form-group">
          <label>Department :</label> 
          <select class="form-control" formControlName="category">
            <option *ngFor ="let item of categories" value="{{item.name}}">{{item.name}}</option>
          </select>
        </div>
        <button class="btn btn-primary btn-block">Submit</button>
      </form>
    </div>
    <p>Form Element : {{formTamo.value | json}}</p>
  </div>

</div><!-- End of container div -->