Angular Model-Driven

Angular Model-Driven (Reactive) Forms

Forms come handy when handling user-input and enabling user to log in, update information, and other data-entry tasks. These are basically used to capture user input events. In Angular, there are two approaches to handling user inputs.
  • Template-Driven Forms
  • Reactive Forms

Template Driven Forms

Template Driven Forms are used to bind the data to the component class using ngModel. We do not need to take the pain of writing code and most of the task is done by Angular itself. There is very less of effort required from the developer to pass information from the component class to the template.

Reactive forms

However, Reactive forms are synchronous and are usually considered when working with database. We write the code for validation inside the component class and also map the objects to the form controls on the view.
In this article, our focus is to work with Reactive Forms which follow the model-driven approach to work with user input and handle it dynamically.

GETTING STARTED WITH REACTIVE FORMS

We will create a Form, using FormGroup, FormControl, FormBuilder class etc. The very first step is to import ReactiveFormsModule in the app.module.ts as listed below :
  1. import { BrowserModule } from '@angular/platform-browser';
  2. import { NgModule } from '@angular/core';
  3. import {ReactiveFormsModule} from '@angular/forms';
  4. import { AppComponent } from './app.component';
  5.  
  6. @NgModule({
  7. declarations: [
  8. AppComponent
  9. ],
  10. imports: [
  11. BrowserModule, ReactiveFormsModule
  12. ],
  13. providers: [],
  14. bootstrap: [AppComponent]
  15. })
  16. export class AppModule { }
Now there are some important classes that need to be imported inside the component like FormControl, FormArray like listed below :
  1. import { Component } from '@angular/core';
  2. import {FormArray, FormControl, FormGroup} from '@angular/forms';
  3.  
  4. @Component({
  5. selector: 'app-root',
  6. template: ``
  7. })
  8. export class AppComponent {
  9. title = 'Reactive Forms';
  10.  
  11. }

Working with FORMCONTROL Class

The FormControl class takes three parameters as input :
  • Initial data value
  • Validators (synchronous)
  • Validators (Asynchronous)
We will focus on validations in the latter portion of this article.
  1. export class AppComponent {
  2. title = 'Forms';
  3. email= new FormControl('');
  4. }
On the template, we can use this FormControl using :
  1. [FormControl] = "email" type ="text" placeholder="What is your email?">

Working with FormGroup Class

Form Controls comprise to become FormGroup. We can think of a FormControl as a child property of FormGroup. The syntax used for FormGroup is as follows
  1. export class AppComponent {
  2. title = 'Forms';
  3. SignIn = new FormGroup({
  4. email: new FormControl(''),
  5. pwd: new FormControl('')
  6. })
  7. }
To use it inside the template
  1. [formGroup]= "SignIn" novalidate class= "form">
  2. [formControl] = "email" type ="text" class="form-control" placeholder="What is your email?"/>
  3. [formControl] = "pwd" type ="text" class="form-control" placeholder="What is your password?"/>

Working with FormBuilder Class

To simplify the syntax of FormGroup and FormControl, we use FormBuilder. This helps reduce the length of our code and optimize it.
  1. constructor(private ff : FormBuilder){
  2. this.SignIn= this.ff.group({
  3. email: [null, [Validators.required, Validators.minLength(4)]],
  4. pwd: [null, [Validators.required, Validators.maxLength(8)]]
  5. })
  6. }

Working with FormArray Class

If you want to add fields in the form dynamically with the help of an array, FormArray is used. Like other classes, it is imported in the component like this :
  1. import {FormArray} from '@angular/forms';
To use it inside the component
  1. this.SignIn = this.ff.group({
  2. email: '',
  3. pwd: ''
  4. items: this.ff.array([ this.crItem() ])
  5. });
On the view
  1. formArrayName="items"
  2. *ngFor="let item of SignIn.get('items').controls; let count = index;">
  3. [formGroupName]="count">
  4. formControlName="email" ">
  5. formControlName="password" >
  • List:
  • Validations

    Till now, we did not add any validation checks to our elements, however, we can do that using Validators in Angular Forms.
    1. import { FormGroup, FormControl, Validators } from '@angular/forms';
    Let us try adding validation to the email field that we created. Inside the component class
    1. ngOnInit() {
    2. this.loginForm = new FormGroup({
    3. email: new FormControl(null, [Validators.required]),
    4. password: new FormControl(null, [Validators.required, Validators.maxLength(8)]),
    5. class: new FormControl(null)
    6. });
    7. }
    On the template
    1. <input formControlName="email" type="text" class="form-control" placeholder="Enter Email" />
    2. <div class="alert alert-danger" *ngIf="loginForm.get('email').hasError('required') && loginForm.get('email').touched">
    3. Email is required
    4. </div>
    5. <input formControlName="password" type="password" class="form-control" placeholder="Enter Password" />
    6. <div class="alert alert-danger" *ngIf="!loginForm.get('password').valid && loginForm.get('email').touched">
    7. Password is required and should less than or equal to 8 characters
    8. </div>
    This will give output as :

    Creating a Reactive Form

    Step 1 :Import ReactiveFormsModule in App Module
    Step 2 :Import FormControl, FormGroup classes in the component class
    Step 3 : Create a FormGroup class with details like email, password
    Step 4 : On the template, create a Submit button with the function to implement submit in the class.
    Putting together everything
    1. import { Component, OnInit } from '@angular/core';
    2. import { FormGroup, FormControl, FormArray, Validators } from '@angular/forms';
    3. @Component({
    4. selector: 'app-root',
    5. template:`
    6. <div class="container">
    7. <br />
    8. <form (ngSubmit)='loginUser()' [formGroup]='loginForm' novalidate class="form">
    9. <input formControlName='email' type="text" class="form-control" placeholder="Enter Email" />
    10. <div class="alert alert-danger" *ngIf="loginForm.get('email').hasError('required') && loginForm.get('email').touched">
    11. Email is required
    12. </div>
    13. <input formControlName='password' type="password" class="form-control" placeholder="Enter Password" />
    14. <div class="alert alert-danger" *ngIf=" !loginForm.get('password').valid && loginForm.get('email').touched">
    15. Password is required and should less than or equal to 8 characters
    16. </div>
    17. <button [disabled]='loginForm.invalid' class="btn btn-default">Login</button>
    18. </form>
    19. </div>
    20. `
    21. })
    22. export class AppComponent implements OnInit {
    23. loginForm: FormGroup;
    24. ngOnInit() {
    25. this.loginForm = new FormGroup({
    26. email: new FormControl(null, [Validators.required, Validators.minLength(4)]),
    27. password: new FormControl(null, [Validators.required, Validators.maxLength(8)])
    28. });
    29. }
    30. loginUser() {
    31. console.log(this.loginForm.status);
    32. console.log(this.loginForm.value);
    33. }
    34. }
    On the browser

    Creating Custom Validations for Angular Reactive Forms

    Now that we have applied validation to email and password, for class we want to create a validation for range such that the class should be from 1 to 12 only. In this case, we will have to write a custom validator as Angular doesn’t provide range validation.So for that, we need to create a function that takes one input parameter of type AbstractControl and returns an object of key value pair in case the validation fails.
    1. function classValidator(control: AbstractControl) : {[key : string] : boolean} | null {
    2. return null;
    3. }
    Here we have created a custom validator named classValidator where the user will be able to enter a class only if it’s in the range that we have provided it. In case of failure of validation, it will return an object which contains key value pair.
    In the component class
    1. class: new FormControl(null, [classValidator])
    On the Template, it goes like :
    1. <input formControlName='Class' type="number" class="form-control" placeholder="Enter Class" />
    2. <div class="alert alert-danger" *ngIf="loginForm.get('class').dirty && loginForm.get('class').errors && loginForm.get('class’).errors.classRange ">
    3. Class should be in between 1 to 12
    4. </div>
    display
    This is how Custom validators help us put validation to our form controls.
    SUMMARY
    In this article, we discussed what are Reactive Forms in Angular. We also saw some of the building blocks of reactive forms and that why reactive forms are beneficial to use. We also created a basic reactive form with some built-in validations in it. Then we created our own custom class validator and applied it to the form.

    Comments

    Popular posts from this blog

    How to Build a Mobile App like Instagram

    Getting started with Web development