Angular Reactive Forms: Introduction and Advantages Over Template-Driven Approach

Introduction

In Angular, we have two types of forms: template-driven forms and reactive forms. In template-driven, most of the logic is written in the template, whereas, in a reactive form, the logic resides mainly in the component or ts file. Reactive forms are more flexible as we can design our own representation of the form. We will create controls programmatically using reactive forms.

There are several advantages of reactive forms over template-driven:
  • We will create our own controls objects explicitly instead of Angular creating it for us. So we will have more control over the form, structure, and behavior.
  • We can write many complex custom validations for the form fields using reactive-forms.
  • Easier to do unit testing with reactive forms.
  • Implement asynchronous validation in which we need to contact the server. Suppose we have a name field and we need to check the uniqueness of the name. So in this case, we need to contact the server to check if the name is unique or not.
  • Using reactive forms, we can add fields dynamically to a form.
  • Build our own custom-validators. Reactive-forms provide much more flexibility than the template-driven approach.
  • Most of the logic resides in the typescript file, thus our templates are much more clean and simple with this approach. 
  •  FormsModule for template-driven forms. To use reactive forms in Angular, we will be using ReactiveFormsModule instead of FormsModule

Reactive Forms In Angular

Generally, we use FormsModule for template-driven forms. To use reactive forms in Angular, we will be using ReactiveFormsModule instead of FormsModule. The first step is to import  this module into our application or respective feature module as follows:

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

@NgModule({
  imports: [
    BrowserModule,
    ReactiveFormsModule,  // Add it here in imports section of ngModule
  ],
  // ...
})
export class AppModule { }

Creating Controls Explicitly For Reactive Forms 

We have an Angular project and a reactive-form component which has a form that has two fields: username and password. We will go to the reactive-form.component.html file and write the below code. Here I have designed a form using Bootstrap. 

<form>
  <div class="form-group">
    <label>Email</label>
    <input type="email" class="form-control" id="userName" placeholder="Enter email">
  </div>
  <div class="form-group">
    <label>Password</label>
    <input type="password" class="form-control" id="password" placeholder="Password">
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

In template-driven forms, we apply the ngModel directive to our input fields and this directive will internally create an instance of the form control class and associated with the input field. Now when we use reactive forms we should create this form control objects explicitly in the code.
In component.ts file, we will import FormGroup and FormControl from @angular/forms. After this, we will define a field using these classes. We will call a form and set it to a new instance of FormGroup object. If we see the constructor of FormGroup, we will see that we have three parameters. Out of these three, two are optional. The first parameter includes the controls that are part of this form.
So here we need to pass an object and the structure of this object should be like this: One or more key-value pairs. The key is a string and value is an abstract control.

What is abstract control?

An abstract control is the base class for FormGroup and FormControl. Both derive their properties from the abstract control class. So the concept here is inheritance. All common properties of FormGroup and FormControl are defined in the abstract base class. Each key is a string and the value is an abstract control.
In our example, we need two key-value pairs. One is for username and another one for the password. So we define keys as username and password and abstract control as FormControl. If we have multiple subgroups in our form, we can declare FormGroup instead of FormControl and again this FormGroup will have FormControl defined.
Write the below code in the reactive-form.component.ts file


import { Component, OnInit} from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
@Component({
  selector: 'app-reactive-form',
  templateUrl: './reactive-form.component.html',
  styleUrls: ['./reactive-form.component.scss']
})
export class ReactiveFormComponent { 

   myForm = new FormGroup({
     username: new FormControl(),
     password: new FormControl()
    });
}

Associating Controls With Template

Now we have to associate the controls to our template. First, we have to apply the formGroup directive to our form element. The name of this field is myForm in our example. Inside this, we have two controls. We have to attach the formControlName directive to the name of the key which we defined in the form group object. In our case, we have named keys: username and password for two fields.

Write the below code in the reactive-form.component.html file

<form [formGroup]="myForm">
  <div class="form-group">
    <label>Email</label>
    <input type="email" class="form-control" id="userName" placeholder="Enter email" formControlName="username">
  </div>
  <div class="form-group">
    <label>Password</label>
    <input type="password" class="form-control" id="password" placeholder="Enter password" formControlName="password">
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

Comments