As explained previously, each form element in angular is represented by an instance of FormControl class which resides in  ‘@angular/forms’  package.

In template driven forms, angular creates instances of FormControl for each form element on its own while in Reactive form type, form elements(or FormControl instances) are created programmatically using classes provided by angular.
Also, in reactive forms, the entire form is represented as a FormGroup.
Thus, all the form elements belong to a FormGroup.
A form can contain other form groups as well which is required when creating complex forms or forms spanning across multiple pages/tabs.

Sample Form

This tutorial will make use of a simple login form with 2 text boxes for user name and password, a check box for remember me functionality and a submit button.
HTML code for the form will be as shown below.

<html>
   <body>
      <form>
        <input type="text" name="userName"/>
        <input type="password" name="password"/>
        <input type="checkbox" name="remember"/>
        <button type="submit">Submit</button>
      </form>
   </body>
</html>

This is a simple form which does not have any angular specific functionality.

Reactive Form Example

Similar to template based form, while creating a reactive form, certain directives are applied to the form and its elements in HTML template.

But in reactive forms, an additional task is required in component class as well.
This task is creating FormGroup object for the form(since a form is a group of controls, hence it is considered as a form group) and FormControl objects for each of the form controls.

Following changes need to done in HTML template and the component class in order to create a reactive form.

A. In Component class

1. An instance of FormGroup needs to be created.
This corresponds to the entire form in HTML template.
2.  Instances of FormControl need to be created.
Each FormControl instance corresponds to a form element inside the HTML template.
A FormControl instance is created using the constructor of FormControl class.
This constructor takes a value which represents the state of the form control or the initial value of the form element.
Each FormControl instance is given a name which is used for binding it with the corresponding HTML form element.

B. In HTML template

1. HTML form is associated with the FormGroup instance created in the component class. This is done by using [formGroup] directive in the  <form>  tag and binding it with the FormGroup instance of the component class.
2. Each form element is associated to a FormControl instance. This is done by using formControlName directive in the HTML form element and binding it with the FormControl instance created the component class. Binding is done by using the name given to the FormControl instance in the component class.

Applying the above changes to the sample form, its HTML template will be modified as below.

<html>
   <body>
      <form [formGroup] = "loginFormGroup">
        <input type="text" formControlName = "username"/>
        <input type="password" formControlName = "password"/>
        <input type="checkbox" formControlName = "remember"/>
        <button type="submit">Submit</button>
      </form>
   </body>
</html>

Notice the use of formGroup and formControlName directives at the form tag and form elements.
Component class for the above HTML template will be

import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { OnInit } from '@angular/core/src/metadata/lifecycle_hooks';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  // form group declaration
  loginFormGroup: FormGroup;

 ngOnInit() {
   // create form group instance
   this.loginFormGroup = new FormGroup({
     'username': new FormControl(''),
     'password': new FormControl(''),
     'remember': new FormControl(true)
   });
 }
}

Component creates a FormGroup instance inside its ngOnInit method using its constructor.
Constructor of FormGroup takes an object which is a collection of key-value pairs.
Value of this object is the FormControl instance and Key of this object is the name with which this FormControl instance should be identified.
Number of FormControl objects in this collection should be equal to the number of form elements in the HTML template.
Note that the name of form group variable(loginFromGroup) matches with the value of [formGroup] directive in the  <form>  tag of HTML template.
Name of each FormControl instance matches with the name given for that control in the HTML template of this form.
Refer image below to grab a better understanding of the concept.
Reactive Form Controls

If the names of formControlName directive in HTML template and FormControl instance in the component class do not match or there is no FormControl instance in the component class corresponding to every form element with formControlName directive in the HTML template, then you will get the below error at the browser console.

ERROR Error: Cannot find control with name: ‘username’

As mentioned earlier, constructor of FormControl takes a value which represents the initial state of the form element.
Thus, if the FormControl instance belongs to a form element which is a text box, then the value supplied to its constructor should be a string and this value will be displayed in the text box.

Similarly, if the FormControl instance belongs to a form element which is a check box, then the value supplied to its constructor should be either true or false.
If it is true then the checkbox will be displayed as checked or it will be unchecked.

Submitting Reactive Form

In order to submit a reactive form, associate its ngSubmit event with a method defined in the corresponding component class. ngSubmit is the output event emitted by the FormGroup. Thus form tag will be modified as below.

<form [formGroup] = “loginFormGroup” (ngSubmit) = “submitForm()”>

Component class will be modified to contain the submit event handler method.

import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { OnInit } from '@angular/core/src/metadata/lifecycle_hooks';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
  // form group declaration
  loginFormGroup: FormGroup;

 ngOnInit() {
   // create form group instance
   this.loginFormGroup = new FormGroup({
     'username': new FormControl(''),
     'password': new FormControl(''),
     'remember': new FormControl(true)
   });
 }
 
 /**
  * Submit event handler method
  */
 submitForm() {
   console.log(this.loginFormGroup.value);
 }
}

Above event handler method is called when the form is submitted and it prints the form value. It prints the following output.
Keys are the names with which form controls were created(username, password and remember) while values are the values typed by the user.

 

{username: “DemoUser”, password: “1234”, remember: true}
   passwordDemoUser
   remembertrue
   username1234

In order to submit the form to the server, you could collect all the form control values into an object and send it to server using http service provided by angular.
Thus submitForm() method can be modified as below.

submitForm() {
  // initialize object to hold form data
  const serverData = {};
  // get form values
  const formData = this.loginFormGroup.value;
  // get value of user name and set it in object
  formData['username'] = formData['username']
  formData['password'] = formData['password']
  formData['remember'] = formData['remember']
  // code to send form data to server using http service
}

Conclusion 

Reactive forms offer a powerful and flexible way to handle form input validation and management in Angular applications.
Through this article, we’ve explored the fundamental concepts of reactive forms, understanding their dynamic nature and ability to react to changes in user input.
The Reactive Form Example section provided a hands-on demonstration of creating a reactive form, defining form controls, applying validation rules, and accessing form data.
Finally, we discussed the process of submitting a reactive form, emphasizing the importance of form validity checks before processing form data.
By mastering reactive forms, developers can streamline the development process, enhance user experience, and ensure data integrity in their Angular applications.

Leave a Reply