Angular Material Design Components With Reactive Form - Part Two

This is a continuation part of Angular material component with Reactive forms, in which we are going to learn how to implement reactive forms with Angular material controls. FormControl, FormGroup, formControlName, ngSubmit.

Introduction
 
This is a continuation of my previous post, How to Develop Reactive Form with Angular Material.
 
Please refer to the following link before going on with the current article,
So let's start by implementing Reactive form with Angular 5
 
What is Reactive Form In Angular? 
 
As we know there are primarily two types of forms available in Angular, 
  1.    Template-driven Forms
  2.    Reactive Forms 
Reactive form in Angular is a technique to manage your form in a reactive manner, it means that you can manage your form and validation from our component itself.
 
These forms are the best option when we have a complex form requirement.
 
Compared to Template driven forms, reactive forms are more suitable because we can define validations and model from component, that gives us more control on form.
 
Primarily it is also called "Model Driven Forms" , because model acts as a mediator between component and template. 
 
It's really easy to implement,  like using model in controller with form control object and binding it to component formcontrol template.
 
Some related terms are below,
 
FormControl
 
In Reactive forms we initialize FormControl object to use form functionality into our component, which engaged with our html form.
 
And when we update our form control's value than it will directly be reflected to our FormControl object that we created previously.  
 
FormGroup 
 
By using FormGroup, it binds all form controls together with some option's.
 
like :- Validations, name of input control etc ...
 
Step 1   
 
First step is to import necessary package to use Reactive form in our App
 
Add following lines to our app.component.ts file,
  1. import { FormBuilder, FormGroup, Validators ,FormsModule,NgForm } from '@angular/forms';  
So after that we can use all the functionality related to Reactive Forms 
 
And do not forgot to include ReactiveForm module in module.ts file,
  1. import { FormsModule,ReactiveFormsModule } from '@angular/forms';  
So as below there is my final module.ts file snippet,
  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule } from '@angular/core';  
  3. import { FormsModule,ReactiveFormsModule } from '@angular/forms';  
  4. import {  
  5.   MatButtonModule,  
  6.   MatMenuModule,  
  7.   MatToolbarModule,  
  8.   MatIconModule,  
  9.   MatCardModule,  
  10.   MatFormFieldModule,  
  11.   MatInputModule,  
  12.   MatDatepickerModule,  
  13.   MatDatepicker,  
  14.   MatNativeDateModule,  
  15.   MatRadioModule,  
  16.   MatSelectModule,  
  17.   MatOptionModule,  
  18.   MatSlideToggleModule,ErrorStateMatcher,ShowOnDirtyErrorStateMatcher  
  19. } from '@angular/material';  
  20. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';  
  21. import { AppComponent } from './app.component';  
  22.   
  23. @NgModule({  
  24.   declarations: [  
  25.     AppComponent  
  26.   ],  
  27.   imports: [  
  28.     BrowserModule,  
  29.     FormsModule,  
  30.     ReactiveFormsModule,  
  31.     MatButtonModule,  
  32.     MatMenuModule,  
  33.     MatToolbarModule,  
  34.     MatIconModule,  
  35.     MatCardModule,  
  36.     BrowserAnimationsModule,  
  37.     MatFormFieldModule,  
  38.     MatInputModule,  
  39.     MatDatepickerModule,  
  40.     MatNativeDateModule,  
  41.     MatRadioModule,  
  42.     MatSelectModule,  
  43.     MatOptionModule,  
  44.     MatSlideToggleModule  
  45.   ],  
  46.   exports: [  
  47.     MatButtonModule,  
  48.     MatMenuModule,  
  49.     MatToolbarModule,  
  50.     MatIconModule,  
  51.     MatCardModule,  
  52.     BrowserAnimationsModule,  
  53.     MatFormFieldModule,  
  54.     MatInputModule,  
  55.     MatDatepickerModule,  
  56.     MatNativeDateModule,  
  57.     MatRadioModule,  
  58.     MatSelectModule,  
  59.     MatOptionModule,  
  60.     MatSlideToggleModule  
  61.   ],  
  62.   providers: [  
  63.     {provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher}  
  64.   ],  
  65.   bootstrap: [AppComponent]  
  66. })  
  67. export class AppModule { }  
So far we have configured our component and module file for working with reactive form .
Step 2 
 
Now let's move to html portion of this demo.
 
For reactive forms we need some important elements as below,
 
FormGroup
  1. <form [formGroup]="regiForm">  
  2. </form>  
here [formGroup] binds our controls as Group structure where each and every control resides within form binds with FormGroup object , which we will discuss later on this post .
 
(ngSubmit) 
  1. <form (ngSubmit)="onFormSubmit(regiForm.value)">  
  2. </form>  
ngSubmit is primary event for our form , when we submit our form this event will be triggered and based on that regiForm[formGroup.value] , we are passing all the values to the component where we have already declared there .
 
formControlName
 
Every control we are using in form should have this directive , and its value is always same as we defined in our component.
 
Generally formcontrolname binds form control to component. 
 
Step 3
 
Now it's time for some Validations. As we know, every form is useless if there are no validations, so we are going to see some important portion of validations.
 
In angular reactive forms, there are some statuses defined as per conditions  like,
  • valid: if form's value are normal and as expected
  • invalid: if there is lack of valid values
  • touched: if we touched any control and have not provided values
  • dirty: returns true only when control was modified 
  • pristine: returns true when no control was modified
So based on your requirement, you can use either of them.
 
For example
  1. <span *ngIf="!regiForm.get('FirstName').valid && regiForm.get('FirstName').touched">Please enter First Name  
  2. </span>  
regiForm is an FormGroup object with which we are going to engage our form controls , and by using their defined value like
 
E.g

FirstName, LastName, we get to know if either of them are valid.
 
Step 4 
 
So far we have created and used all basic functionality that Reactive forms should have.
 
Please see the below snippet for better understanding,
  1. <!-- Main Toolbar of an App -->  
  2. <mat-toolbar color="accent">  
  3.     <span>Manav Pandya - C#Corner</span>  
  4.     <span class="demo-toolbar"></span>  
  5.     <button mat-button href="asp-dotnet-mvc-tutorials.blogspot.in">Go To My Blog</button>  
  6.   
  7. </mat-toolbar>  
  8.   
  9. <!-- Card container that binds all togather -->  
  10. <mat-card>  
  11.     <!-- Title of an Card -->  
  12.     <mat-card-title>  
  13.         Angular Material Component With Angular 5  
  14.     </mat-card-title>  
  15.   
  16.     <!-- Actual content starts from here -->  
  17.     <mat-card-content>  
  18.         <form [formGroup]="regiForm" (ngSubmit)="onFormSubmit(regiForm.value)">  
  19.             <table>  
  20.                 <tr>  
  21.                     <td>  
  22.                         <mat-form-field class="demo-full-width">  
  23.                             <input formControlName="FirstName" matInput placeholder="First Name">  
  24.                         </mat-form-field>  
  25.                         <mat-error>  
  26.                             <span *ngIf="!regiForm.get('FirstName').valid && regiForm.get('FirstName').touched">Please enter First Name !!!</span>  
  27.                         </mat-error>  
  28.                     </td>  
  29.                     <td>  
  30.                         <mat-form-field class="demo-full-width">  
  31.                             <input formControlName="LastName" matInput placeholder="Last Name">  
  32.                         </mat-form-field>  
  33.                         <mat-error>  
  34.                             <span *ngIf="!regiForm.get('LastName').valid && regiForm.get('LastName').touched">Please enter Last Name !!!</span>  
  35.                         </mat-error>  
  36.                     </td>  
  37.                 </tr>  
  38.                 <tr>  
  39.                     <td colspan="2">  
  40.                         <mat-form-field class="demo-full-width">  
  41.                             <textarea formControlName="Address" matInput placeholder="Address" matTextareaAutosize matAutosizeMinRows="2" matAutosizeMaxRows="5"></textarea>  
  42.                         </mat-form-field>  
  43.                         <mat-error>  
  44.                             <span *ngIf="!regiForm.get('Address').valid && regiForm.get('Address').touched">Please enter proper address !!!</span>  
  45.                         </mat-error>  
  46.                     </td>  
  47.                 </tr>  
  48.                 <tr>  
  49.                     <td colspan="2">  
  50.                         <mat-form-field class="demo-full-width">  
  51.                             <input formControlName="DOB" matInput [matDatepicker]="picker" placeholder="Date of birth">  
  52.                             <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>  
  53.                             <mat-datepicker touchUi="true" #picker></mat-datepicker>  
  54.                         </mat-form-field>  
  55.                         <mat-error>  
  56.                             <span *ngIf="!regiForm.get('DOB').valid && regiForm.get('DOB').touched">Please select any Date !!!</span>  
  57.                         </mat-error>  
  58.                     </td>  
  59.                 </tr>  
  60.                 <tr>  
  61.                     <td>  
  62.                         <span>Gender</span><br><br>  
  63.                         <mat-radio-group formControlName="Gender">  
  64.                             <mat-radio-button value="Male">Male</mat-radio-button>  
  65.                             <mat-radio-button value="Female">Female</mat-radio-button>  
  66.                         </mat-radio-group>  
  67.                         <mat-error>  
  68.                             <span *ngIf="!regiForm.get('Gender').valid && regiForm.get('Gender').touched">Please select any gender !!!</span>  
  69.                         </mat-error>  
  70.                     </td>  
  71.                     <td><br>  
  72.                         <mat-form-field>  
  73.                             <mat-select formControlName="Blog" placeholder="Select Blog">  
  74.                                 <mat-option>-- Select Any --</mat-option>  
  75.                                 <mat-option value="C#Corner">C#Corner</mat-option>  
  76.                                 <mat-option value="C#Corner">C#Corner</mat-option>  
  77.                                 <mat-option value="C#Corner">C#Corner</mat-option>  
  78.                             </mat-select>  
  79.                             <mat-error>  
  80.                                 <span *ngIf="!regiForm.get('Blog').valid && regiForm.get('Blog').touched">Please select any item !!!</span>  
  81.                             </mat-error>  
  82.                         </mat-form-field>  
  83.                     </td>  
  84.                 </tr>  
  85.                 <tr>  
  86.                     <td colspan="2">  
  87.                         <mat-form-field class="demo-full-width">  
  88.                             <input formControlName="Email" matInput placeholder="Email">  
  89.                             <mat-hint>use like : demo@demo.com</mat-hint>  
  90.                             <mat-error>  
  91.                                 <span *ngIf="!regiForm.get('Email').valid && regiForm.get('Email').touched">Enter proper Email !!!</span>  
  92.                             </mat-error>  
  93.                         </mat-form-field>  
  94.                     </td>  
  95.                 </tr>  
  96.                 <tr>  
  97.                     <td colspan="2">  
  98.                         <mat-slide-toggle formControlName="IsAccepted" (change)="onChange($event)">Accept Terms & Conditions</mat-slide-toggle>  
  99.                     </td>  
  100.                 </tr>  
  101.                 <tr>  
  102.                     <td colspan="2" class="content-center">  
  103.                         <button mat-raised-button color="accent" [disabled]="!regiForm.valid || IsAccepted==0">Submit</button>  
  104.                     </td>  
  105.                 </tr>  
  106.                 <tr>  
  107.                     <td></td>  
  108.                 </tr>  
  109.             </table>  
  110.         </form>  
  111.     </mat-card-content>  
  112. </mat-card>  
Step 5
 
For binding our Form controls, we should call FormControl from our component, that binds all template controls to our form elements.
 
For that I have used FormGroup, which holds all the template elements that we have used in our template [html portion]. 
  1. // By : Manav Pandya  
  2.   
  3. import { Component } from '@angular/core';  
  4.   
  5. // Must import to use Forms functionality  
  6. import { FormBuilder, FormGroup, Validators ,FormsModule,NgForm } from '@angular/forms';  
  7.   
  8. @Component({  
  9.   selector: 'app-root',  
  10.   templateUrl: './app.component.html',  
  11.   styleUrls: ['./app.component.css']  
  12. })  
  13.   
  14. export class AppComponent {  
  15.     
  16.   regiForm: FormGroup;  
  17.   FirstName:string='';  
  18.   LastName:string='';  
  19.   Address:string='';  
  20.   DOB:Date=null;  
  21.   Gender:string='';  
  22.   Blog:string='';  
  23.   Email:string='';  
  24.   IsAccepted:number=0;  
  25.   
  26.   constructor(private fb: FormBuilder) {   
  27.   
  28.   
  29.     // To initialize FormGroup  
  30.     this.regiForm = fb.group({  
  31.       'FirstName' : [null, Validators.required],  
  32.       'LastName' : [null, Validators.required],  
  33.       'Address' : [null, Validators.compose([Validators.required, Validators.minLength(30), Validators.maxLength(500)])],  
  34.       'DOB' : [null, Validators.required],  
  35.       'Gender':[null, Validators.required],  
  36.       'Blog':[null, Validators.required],  
  37.       'Email':[null, Validators.compose([Validators.required,Validators.email])],  
  38.       'IsAccepted':[null]  
  39.     });  
  40.   
  41.   }  
  42.   
  43.   // On Change event of Toggle Button  
  44.   onChange(event:any)  
  45.   {  
  46.     if (event.checked == true) {  
  47.       this.IsAccepted = 1;  
  48.     } else {  
  49.       this.IsAccepted = 0;  
  50.     }  
  51.   }  
  52.   
  53.   // Executed When Form Is Submitted  
  54.   onFormSubmit(form:NgForm)  
  55.   {  
  56.     console.log(form);  
  57.   }  
  58.     
  59. }  
As you can see I have provided comments so you can understand easily why I've used them.
 
Apart from the constructor, I also used 2 methods with it,
  • onChange(): to trigger value of toggle button to locate its value, and based on the value iIm enabling or disabling submit button.
  • onFormSubmit(): Our base method which is used to get all the values of a form when the user submits the form, and also I have logged submitted data to console, so we will get to know the data captured.  
Final Output
 
open browser console and you can see output like this.
 
 
Conclusion
 
Let's wrap up this second part of the series of Angular material with Reactive forms.
 
So far we have learned,
  • Angular Material Component
  • Reactive Form
  • Form Validations
If I missed anything, feel free make suggestions anytime.
 
Stay tuned for some interesting articles.