Reactive Forms And Validation In Angular With Typescript

This article will give you extensive information about Reactive Forms and Model-Driven Forms, and how to create the form using the Reactive Forms approach and implement the validation with Angular 6 and TypeScript. 

In the previous article, "Template Driven Forms and Validation in Angular with Typescript", we have learned what Template-Driven Forms are, how to create these, and implement validations. If you don't know about Template-Driven Forms, I recommend you read the previous article as well. Now, let's move to Reactive Forms and understand what they are and how to create Reactive Forms in Angular and how to implement the validation with Reactive Forms or Model-Driven Forms.

Model-Driven Forms and Reactive Forms

As the name suggests, in this approach, to create forms, we focus on the component code more than the template code. It means to say that while creating the forms and validation, everything is written inside the component so that the logic will be inside the component class which makes the templates easy to understand. The Reactive Forms approach basically avoids the directives like ngModel and Required. Here, it doesn't focus on Template to make forms and validations but instead of that, we use the power of Angular. As we have available everything on the code, it means in the component class. So, it becomes very easy to test your forms without any complexity. 

After the end of this demonstration, you will get the application like below, with implementation of Reactive Forms and Validations.

Reactive Forms And Validation In Angular With Typescript

IMPLEMENTATION OF REACTIVE FORMS

So, let's understand the Reactive Forms in more detailed ways. For understanding it, first, we will create an Angular 6 project. If you don't have an idea of how to create an Angular project, just read the above articles. For this demonstration, we are using the same Angular CLI project which we have already created for our previous article of Template Driven Forms. So, let us open the project and go to app.module.ts file and add ReactiveFormsModule which is imported from @angular/forms. It will provide all the required components for the Reactive Forms.

  1. import { FormsModule, ReactiveFormsModule } from '@angular/forms';  

After adding the ReactiveFormsModule in AppModule, it's time to add a new component class as 'ReactiveFormComponent' using the command 'ng g c TemplateDrivenForm'. We are working on the project which we have created in the previous article for Template Driven Forms. So, you will find both the components available in AppModule as below.

  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule } from '@angular/core';  
  3. import { FormsModule, ReactiveFormsModule } from '@angular/forms';  
  4.   
  5. import { AppRoutingModule } from './app-routing.module';  
  6. import { AppComponent } from './app.component';  
  7. import { TemplateDrivenFormComponent } from './template-driven-form/template-driven-form.component';  
  8. import { ReactiveFormComponent } from './reactive-form/reactive-form.component';  
  9.   
  10. @NgModule({  
  11.   declarations: [  
  12.     AppComponent,  
  13.     TemplateDrivenFormComponent,  
  14.     ReactiveFormComponent  
  15.   ],  
  16.   imports: [  
  17.     BrowserModule,  
  18.     FormsModule,  
  19.     ReactiveFormsModule,  
  20.     AppRoutingModule  
  21.   ],  
  22.   providers: [],  
  23.   bootstrap: [AppComponent]  
  24. })  
  25. export class AppModule { }  

Now, we will create a route for a new component 'ReactiveFormComponent'. So, let us add one path inside the Routes.

  1. import { NgModule } from '@angular/core';  
  2. import { Routes, RouterModule } from '@angular/router';  
  3. import { ReactiveFormComponent } from 'src/app/reactive-form/reactive-form.component';  
  4. import { TemplateDrivenFormComponent } from 'src/app/template-driven-form/template-driven-form.component';  
  5.   
  6. const routes: Routes = [  
  7.   {  
  8.     path: 'reactiveform',  
  9.     pathMatch: 'full',  
  10.     component: ReactiveFormComponent  
  11.   },  
  12.   {  
  13.     path: 'templateform',  
  14.     pathMatch: 'full',  
  15.     component: TemplateDrivenFormComponent  
  16.   }  
  17.   
  18. ];  
  19.   
  20. @NgModule({  
  21.   imports: [RouterModule.forRoot(routes)],  
  22.   exports: [RouterModule]  
  23. })  
  24. export class AppRoutingModule { }  

Above, we have configured our AppModule and AppRoutingModule for a newly added component 'ReactiveFormComponent'. Now onwards, we will write the actual code for implementing the Reactive Forms. Before moving to the actual implementation, we should be aware of a few keywords, which will frequently be used in the coming code.

  • FormBuilder
    It helps us to create extensive and complex forms using FormGroup, FormControl, FormArrary etc in an easy way.

  • FormGroup
    It creates the group of form's elements using the list of controls and tracks the values for these controls.

  • FormControl
    It is a class for creating and tracking the values and validations for individual control.

  • FormControlName
    It is a directive which is used to map the model's control name to the template. 

  • FormGroupName
    It's a nested FormGroup. If you are willing to create the form group inside the form group then you can use FormGroupName.

  • Validators
    It is a function that validates the data for the form control or list of form controls and returns the error or null.

After understanding the above keywords and their uses, we will move next to a demonstration of Reactive Forms. So, let's import these inside the ReactiveFormsComponent.

  1. import { FormGroup, FormBuilder, Validators, FormControl, NgForm } from '@angular/forms';  

FormControl is used to create a form of control from the component class and Validators is used to validate that control using different types of validations attributes. You can see with the following code, how we create a control as 'email' and add the four different types of validations like required validation, minlength validation, maxlength validation and pattern matching validation. So, this way, you can create the control for the form group and add the validation.

  1. email: new FormControl('', [  
  2.         Validators.required,  
  3.         Validators.minLength(5),  
  4.         Validators.maxLength(80),  
  5.         Validators.pattern("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$")  
  6.       ]),  

Now, let's move to actual code implementation inside the ReactiveFormComponent. So, first let's get the instance of FormBuilder using Constructor Dependency Injection and create a reference of FormGroup. After that, you can create multiple controls for the form group 'registrationForm'  similar to how we have given a sample control creation technique above. For getting the form's controls value on submitting the form, we have created on method as 'onRegistrationFormSubmit()'. In this method, first, we will check if our form is valid or not. Once the form will be valid then we can get the value of the control. You can see with the below code how we have created ReactiveFormComponent.

  1. import { Component, OnInit } from '@angular/core';  
  2. import { FormGroup, FormBuilder, Validators, FormControl, NgForm } from '@angular/forms';  
  3. import { FormArray } from '@angular/forms/src/model';  
  4.   
  5. @Component({  
  6.   selector: 'app-reactive-form',  
  7.   templateUrl: './reactive-form.component.html',  
  8.   styleUrls: ['./reactive-form.component.css']  
  9. })  
  10. export class ReactiveFormComponent implements OnInit {  
  11.   registrationForm: FormGroup;  
  12.   isSubmitted: boolean = false;  
  13.   
  14.   constructor(private formBuilder: FormBuilder) {  
  15.     this.registrationForm = this.formBuilder.group({  
  16.       firstName: new FormControl('', [  
  17.         Validators.required,  
  18.         Validators.minLength(3),  
  19.         Validators.maxLength(30),  
  20.         Validators.pattern('^[a-zA-Z ]*$')]),  
  21.       lastName: new FormControl('', []),  
  22.       addressGroup: this.formBuilder.group({  
  23.         address: new FormControl('', [  
  24.           Validators.required,  
  25.           Validators.maxLength(255)  
  26.         ]),  
  27.         city: new FormControl('', []),  
  28.         state: new FormControl('', []),  
  29.         pincode: new FormControl('', [  
  30.           Validators.required,  
  31.           Validators.minLength(6),  
  32.           Validators.maxLength(8),  
  33.           Validators.pattern('^[a-zA-Z0-9]*$')])         
  34.       }),  
  35.       phoneNumber: new FormControl('', [  
  36.         Validators.required,  
  37.         Validators.minLength(8),  
  38.         Validators.maxLength(12),  
  39.         Validators.pattern('^[0-9]*$')]),  
  40.       email: new FormControl('', [  
  41.         Validators.required,  
  42.         Validators.minLength(5),  
  43.         Validators.maxLength(80),  
  44.         Validators.pattern("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$")  
  45.       ]),  
  46.       password: new FormControl('', [  
  47.         Validators.required,  
  48.         Validators.minLength(5),  
  49.         Validators.maxLength(12)          
  50.       ])  
  51.     });  
  52.   }  
  53.   
  54.   ngOnInit() {  
  55.   
  56.   }  
  57.   
  58.   onRegistrationFormSubmit() {  
  59.     this.isSubmitted = true;  
  60.     if(this.registrationForm.valid){        
  61.       console.log("User Registration Form Submit"this.registrationForm.value);  
  62.     }  
  63.       
  64.   }  
  65. }  

Now, it's time to create the DOM element in the template for the model. So, first let's understand how we will create the form control inside the template which maps with model control. So, for using the control, which we have already created in Component class, we will use formControlName directive along with the control name as follows.

  1. <input type="text" placeholder="Enter First Name Here.." formControlName="firstName" class="form-control" />  

And for creating the different types of the error messages for different types of validation failure, we will create a template similar to the below one. This is just a sample. Here, you can see, before any validation message is going to show, we are checking two things, first "Is there any error with particular control" and second "Is form submitted". If both return true then we will move to the inner template where we have defined different template codes for different types of errors.

  1. <div *ngIf="registrationForm.get('firstName').errors  && isSubmitted">  
  2.  <div *ngIf="registrationForm.get('firstName').hasError('required')">  
  3.    <span style="color: red;">Please Enter First Name.</span>  
  4.  </div>  
  5.  <div *ngIf="registrationForm.get('firstName').hasError('minlength')">  
  6.    <span style="color: red;">First Name requied atleast 3 characters.</span>  
  7.  </div>  
  8.  <div *ngIf="registrationForm.get('firstName').hasError('maxlength')">  
  9.   <span style="color: red;">First Name requied only 30 characters.</span>  
  10.  </div>  
  11.  <div *ngIf="registrationForm.get('firstName').hasError('pattern')">  
  12.   <span style="color: red;">Only characters are allowed.</span>  
  13.  </div>  
  14. </div>  

Here is the full code for reactive-form.component.html. Here, we are going to implement a registration form with different types of controls and their validations.

  1. <div class="container">  
  2.   <h3 class="well">Registration Form</h3>  
  3.   <div class="row">  
  4.     <form [formGroup]="registrationForm" (ngSubmit)="onRegistrationFormSubmit()">  
  5.       <div class="col-sm-12">  
  6.         <div class="row">  
  7.           <div class="col-sm-6 form-group">  
  8.             <label>First Name</label>  
  9.             <input type="text" placeholder="Enter First Name Here.." formControlName="firstName" class="form-control" />  
  10.             <div *ngIf="registrationForm.get('firstName').errors  && isSubmitted">  
  11.               <div *ngIf="registrationForm.get('firstName').hasError('required')">  
  12.                 <span style="color: red;">Please Enter First Name.</span>  
  13.               </div>  
  14.               <div *ngIf="registrationForm.get('firstName').hasError('minlength')">  
  15.                 <span style="color: red;">First Name requied atleast 3 characters.</span>  
  16.               </div>  
  17.               <div *ngIf="registrationForm.get('firstName').hasError('maxlength')">  
  18.                 <span style="color: red;">First Name requied only 30 characters.</span>  
  19.               </div>  
  20.               <div *ngIf="registrationForm.get('firstName').hasError('pattern')">  
  21.                 <span style="color: red;">Only characters are allowed.</span>  
  22.               </div>  
  23.             </div>  
  24.           </div>  
  25.           <div class="col-sm-6 form-group">  
  26.             <label>Last Name</label>  
  27.             <input type="text" placeholder="Enter Last Name Here.." formControlName="lastName" class="form-control" />  
  28.           </div>  
  29.         </div>  
  30.         <div formGroupName="addressGroup" class="form-group">  
  31.           <label>Address</label>  
  32.           <textarea placeholder="Enter Address Here.." rows="2" formControlName="address" class="form-control"></textarea>  
  33.           <div *ngIf="registrationForm.get('addressGroup.address').errors && isSubmitted">  
  34.             <div *ngIf="registrationForm.get('addressGroup.address').hasError('required')">  
  35.               <span style="color: red;">Please Enter Address.</span>  
  36.             </div>  
  37.             <div *ngIf="registrationForm.get('addressGroup.address').hasError('maxlength')">  
  38.               <span style="color: red;">Only 255 characters are allowed.</span>  
  39.             </div>  
  40.           </div>  
  41.         </div>  
  42.         <div formGroupName="addressGroup" class="row">  
  43.           <div class="col-sm-4 form-group">  
  44.             <label>City</label>  
  45.             <input type="text" placeholder="Enter City Name Here.." formControlName="city" class="form-control" />  
  46.           </div>  
  47.           <div class="col-sm-4 form-group">  
  48.             <label>State</label>  
  49.             <input type="text" placeholder="Enter State Name Here.." formControlName="state" class="form-control" />  
  50.           </div>  
  51.           <div class="col-sm-4 form-group">  
  52.             <label>PinCode</label>  
  53.             <input type="text" placeholder="Enter Zip Code Here.." formControlName="pincode" class="form-control" />  
  54.             <div *ngIf="registrationForm.get('addressGroup.pincode') && isSubmitted">  
  55.               <div *ngIf="registrationForm.get('addressGroup.pincode').hasError('required')">  
  56.                 <span style="color: red;">Please Enter PinCode.</span>  
  57.               </div>  
  58.               <div *ngIf="registrationForm.get('addressGroup.pincode').hasError('minlength')">  
  59.                 <span style="color: red;">PinCode requied atleast 6 characters.</span>  
  60.               </div>  
  61.               <div *ngIf="registrationForm.get('addressGroup.pincode').hasError('maxlength')">  
  62.                 <span style="color: red;">PinCode requied only 8 characters.</span>  
  63.               </div>  
  64.               <div *ngIf="registrationForm.get('addressGroup.pincode').hasError('pattern')">  
  65.                 <span style="color: red;">Only alph-numerics are allowed.</span>  
  66.               </div>  
  67.             </div>  
  68.           </div>  
  69.         </div>  
  70.         <div class="form-group">  
  71.           <label>Phone Number</label>  
  72.           <input type="text" placeholder="Enter Phone Number Here.." formControlName="phoneNumber" class="form-control" />  
  73.           <div *ngIf="registrationForm.get('phoneNumber').errors && isSubmitted">  
  74.             <div *ngIf="registrationForm.get('phoneNumber').hasError('required')">  
  75.               <span style="color: red;">Please Enter Phone Number.</span>  
  76.             </div>  
  77.             <div *ngIf="registrationForm.get('phoneNumber').hasError('minlength')">  
  78.               <span style="color: red;">Phone Number requied atleast 8 characters.</span>  
  79.             </div>  
  80.             <div *ngIf="registrationForm.get('phoneNumber').hasError('maxlength')">  
  81.               <span style="color: red;">Phone Number requied only 12 characters.</span>  
  82.             </div>  
  83.             <div *ngIf="registrationForm.get('phoneNumber').hasError('pattern')">  
  84.               <span style="color: red;">Only Numbers are allowed.</span>  
  85.             </div>  
  86.           </div>  
  87.         </div>  
  88.         <div class="row">  
  89.           <div class="col-sm-6 form-group">  
  90.             <label>Email Address</label>  
  91.             <input type="text" placeholder="Enter Email Address Here.." formControlName="email" class="form-control" />  
  92.             <div *ngIf="registrationForm.get('email').errors && isSubmitted">  
  93.               <div *ngIf="registrationForm.get('email').hasError('required')">  
  94.                 <span style="color: red;">Please Enter Email.</span>  
  95.               </div>  
  96.               <div *ngIf="registrationForm.get('email').hasError('minlength')">  
  97.                 <span style="color: red;">The email requied atleast 5 characters.</span>  
  98.               </div>  
  99.               <div *ngIf="registrationForm.get('email').hasError('maxlength')">  
  100.                 <span style="color: red;">The email requied only 80 characters.</span>  
  101.               </div>  
  102.               <div *ngIf="registrationForm.get('email').hasError('pattern')">  
  103.                 <span style="color: red;">The Email is not valid.</span>  
  104.               </div>  
  105.             </div>  
  106.           </div>  
  107.           <div class="col-sm-6 form-group">  
  108.             <label>Password</label>  
  109.             <input type="password" placeholder="Enter Password Here.." formControlName="password" class="form-control" />  
  110.             <div *ngIf="registrationForm.get('password').errors && isSubmitted">  
  111.               <div *ngIf="registrationForm.get('password').hasError('required')">  
  112.                 <span style="color: red;">Please Enter Password.</span>  
  113.               </div>  
  114.               <div *ngIf="registrationForm.get('password').hasError('minlength')">  
  115.                 <span style="color: red;">The password requied atleast 5 characters.</span>  
  116.               </div>  
  117.               <div *ngIf="registrationForm.get('password').hasError('maxlength')">  
  118.                 <span style="color: red;">The password requied only 12 characters.</span>  
  119.               </div>  
  120.             </div>  
  121.           </div>  
  122.         </div>  
  123.         <button type="submit" class="btn btn-lg btn-info">Submit</button>  
  124.       </div>  
  125.     </form>  
  126.   </div>  
  127. </div>  

Now, let us run the application using the command 'ng serve --open'.

Finally, you will get the output similar to the screenshot we have added in the beginning of the article. 

Conclusion

So, today we have learned about Reactive Forms in Angular and how to create them and add validations.

I hope this post will help you. Please put your feedback using comments which help me to improve myself for the next post. If you have any doubts, please ask your doubts or query in the comment section. If you like this post, please share it with your friends.