Reactive/Model-Driven Forms

Introduction

 
In this article, we are going to explore the steps to add Reactive/Model-driven Forms in an Angular application and the advantages of using them in the application.
 

Overview

 
We can create forms in a reactive style in Angular. We need to create form control objects in a component class and should bind them with HTML form elements in the template. A component can observe the form of control state changes and react to them.
 
Here, we will be using FormBuilder class to create reactive forms, which have a simplified syntax. We need to import ReactiveFormsModule to create reactive forms. We can use built-in validators using the Validators class. For example, if we want to use the 'required' validator, it can be accessed as Validators.required.
 

Advantages of Reactive/Model-driven Forms

  • We can listen to form changes or events easily using reactive forms. Each FormGroup or FormControl has few events like valueChanges, statusChanges, etc., which we can subscribe to.
  • Model-driven forms are used in creating medium to large scale applications.
  • We can now perform unit testing (using the Jasmine framework) on the validation logic as it is written inside a component class. 
Demosteps
 
Open app.module.ts and below code to add a reactive form module:
  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule } from '@angular/core';  
  3. import { ReactiveFormsModule } from '@angular/forms';  
  4. import { AppRoutingModule } from './app-routing.module';  
  5. import { AppComponent } from './app.component';  
  6. import {Form, FormsModule} from '@angular/forms';  
  7. import { ArticleFormComponent } from './article-form/article-form.component';  
  8. import { RegistrationFormComponent } from './registration-form/registration-form.component';  
  9. @NgModule({  
  10.   declarations: [  
  11.     AppComponent,  
  12.     ArticleFormComponent,  
  13.     RegistrationFormComponent  
  14.   ],  
  15.   imports: [  
  16.     BrowserModule,  
  17.     AppRoutingModule,  
  18.     FormsModule,  
  19.     ReactiveFormsModule  
  20.   ],  
  21.   providers: [],  
  22.   bootstrap: [AppComponent]  
  23. })  
  24. export class AppModule { }  
Create a component called RegistrationForm using the following CLI command.
 
Add the following code in the registration-form.component.ts file:
  1. import { Component, OnInit } from '@angular/core';  
  2. import { FormBuilder, FormGroup, Validators } from '@angular/forms';  
  3. @Component({  
  4.   selector: 'app-registration-form',  
  5.   templateUrl: './registration-form.component.html',  
  6.   styleUrls: ['./registration-form.component.css']  
  7. })  
  8. export class RegistrationFormComponent implements OnInit {  
  9.   registerForm: FormGroup;
  10.   submitted : Boolean;
  11.   constructor(private formBuilder: FormBuilder) { }  
  12.   ngOnInit() {  
  13.     this.registerForm = this.formBuilder.group({  
  14.       firstName: ['', Validators.required],  
  15.       lastName: ['', Validators.required],  
  16.       address: this.formBuilder.group({  
  17.         street: [],  
  18.         zip: [],  
  19.       })  
  20.     });  
  21.   }  
  22. }  
Line 2: Import FormBuilder class to create a reactive form. Also, import FormGroup class to create a group of form controls and Validators for validation.
 
Line 09:Create a property registerForm of type FormGroup.
 
Line 11: Inject a formBuilder instance using the constructor.
 
Line 12: Angular has some life cycle methods/hooks to provide visibility into key life moments of a component and the ability to act when they occur.ngOnInit is a lifecycle hook that will be invoked when Angular initializes the directive or component. 
 
Line 13: formBuilder.group() method creates a FormGroup. It takes an object whose keys are FormControl names and values are their definitions. 
 
Line 14-18: Create form controls such as firstName, lastName, and address as a subgroup with fields street, zip, and city. These fields are form controls. Configure built-in validators for each control using [' ', Validators.required] syntax where the first parameter is the default value for the control and the second parameter is an array of validations. If multiple validators are to be applied, then we should give it as [' ', [Validators.required,Validators.maxlength(10)]] .
 
Add the below code in registration-form.component.html:
  1. <div class="container">  
  2.     <h1>Registration Form</h1>  
  3.     <form [formGroup]="registerForm">  
  4.       <div class="form-group">  
  5.         <label>First Name</label>  
  6.         <input type="text" class="form-control" formControlName="firstName">  
  7.         <p *ngIf="registerForm.controls.firstName.errors" class="alert alert-danger">This field is required!</p>  
  8.       </div>  
  9.       <div class="form-group">  
  10.         <label>Last Name</label>  
  11.         <input type="text" class="form-control" formControlName="lastName">  
  12.         <p *ngIf="registerForm.controls.lastName.errors" class="alert alert-danger">This field is required!</p>  
  13.       </div>  
  14.       <div class="form-group">  
  15.         <fieldset formGroupName="address">  
  16.           <label>Street</label>  
  17.           <input type="text" class="form-control" formControlName="street">  
  18.           <label>Zip</label>  
  19.           <input type="text" class="form-control" formControlName="zip">  
  20.           <label>City</label>  
  21.           <input type="text" class="form-control" formControlName="city">  
  22.         </fieldset>  
  23.       </div>  
  24.       <button type="submit" (click)="submitted=true">Submit</button>  
  25.     </form>  
  26.   <br/>  
  27.     <div [hidden]="!submitted">  
  28.       <h3> Employee Details </h3>  
  29.       <p>First Name: {{ registerForm.get('firstName').value }} </p>  
  30.       <p> Last Name: {{ registerForm.get('lastName').value }} </p>  
  31.       <p> Street: {{ registerForm.get('address.street').value }}</p>  
  32.       <p> Zip: {{ registerForm.get('address.zip').value }} </p>  
  33.     </div>  
  34.   </div>  
  35.      
Line 27: the div tag will be hidden if the form is not submitted
 
Line 29-32: Using get() method of FormGroup, we are fetching values of each FormControl and rendering it
 
Add the below code in registration-form.component.css:
  1. .ng-valid[required]  {  
  2.   border-left: 5px solid #42A948; /* green */  
  3. }  
  4. .ng-invalid:not(form)  {  
  5.   border-left: 5px solid #a94442; /* red */  
  6. }  
Add below code in app.component.html:
  1. <app-registration-form></app-registration-form>  
Now save the project and observe the output in the browser. You will get the below output screen:
It renders the values at the bottom after clicking the submit button, as shown below:
 
 

Summary

 
In this article, we explored the steps to add Reactive/Model-driven Forms in an Angular application and the advantages of using them. I hope you like the article. Until next time - Happy Reading  Cheers