AppDividend
Latest Code Tutorials

Angular 10 Reactive Forms with Validation Example

2

Reactive forms in Angular 10 provide a model-driven approach to handling form inputs whose values change over time. Reactive Forms can create and update a primary form control, progress to using multiple controls in the group, validate form values, and create dynamic form controls where you can add or remove controls at run time.

Angular 10 Reactive Forms

Reactive Forms use a specific and perpetual approach to managing a state of the form at any given time. Each change to the form state returns the new state, which preserves the integrity of the model between changes.

Reactive forms are developed around observable streams, where form inputs and values are provided as streams of input values, which can be then accessed synchronously.

Reactive forms also provide a sincere path to testing because you are guaranteed that your data is consistent and predictable when requested. Any subscribers of the streams have access to change that data safely.

Reactive forms differ from template-driven forms in clear ways. Reactive forms provide more predictability with synchronous access to the data model, immutability with observable operators, and change tracking through observable streams.

Template-driven forms enable direct access to change data in your template but are less precise than Reactive Forms because they depend on the directives embedded in the template, along with mutable data to track asynchronously.

How to add primary form control in Angular

There are three steps to using form controls.

  1. Register the Reactive Forms module in your app. The ReactiveForms module declares the reactive-form directives that you need to use reactive forms.
  2. Generate the new FormControl instance and save it inside the component.
  3. Register a FormControl in the template.

You can then display the form by adding a component to the template.

Let’s implement all the steps to create and validate Reactive forms in Angular 10.

Step 1: Create a new Angular project

To create an Angular 10 project, you have to install Angular CLI 10.

Type the following command to create the new Angular project.

ng new angularreactive

Go inside the folder and install the Bootstrap CSS Framework.

npm install bootstrap --save

Open an Angular.json file and add the path to the Bootstrap CSS Framework.

"styles": [
  "src/styles.css",
   "./node_modules/bootstrap/dist/css/bootstrap.min.css"
],

Step 2: Register the Reactive Forms module

To use the reactive form controls, import ReactiveFormsModule from the @angular/forms package, and add it to your NgModule’s imports array.

// app.module.ts

import { ReactiveFormsModule } from '@angular/forms';

imports: [
    ...
    ReactiveFormsModule
  ],

Step 3: Import required @angular/forms modules

Write the following code inside the app.component.ts file.

// app.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  loginForm: FormGroup;
  constructor(private fb: FormBuilder) {
  }

  ngOnInit(): void {
    this.initForm();
  }

  initForm(): void {
  }
}

Forms typically contain number of related controls. Reactive forms provide the two ways of grouping multiple similar controls into a single input form.

  1. A FormGroup defines the form with a fixed set of controls that you can manage together. You can nest form groups to create more complex forms.
  2. A FormArray defines the dynamic form, where you can insert and remove controls at run time. You can also use the nest form arrays to create more complex forms.

From @angular/forms, we have imported three modules.

  1. FormGroup
  2. FormBuilder
  3. Validators

Then we have defined a class variable called loginForm, which is a type of FormGroup.

We are using the FormBuilder module to create a Form with different form controls.

Until now, we have just initialized a form but did not register a single form control.

We are building a login form. So, it has two fields.

  1. Email
  2. Password

So, we will create two form controls.

Step 4: Adding a form controls

To register the single form control, import the FormControl class, and create the new instance of FormControl to save as a class property.

Creating form control instances manually can become tedious when dealing with multiple forms. The FormBuilder service provides the appropriate methods for generating controls.

Use the following steps to take advantage of the FormBuilder service.

  1. Import the FormBuilder class.
  2. Inject the FormBuilder service.
  3. Generate the form contents.

So, write the following code inside the app.component.ts file.

// app.component.ts

initForm(): void {
    this.loginForm = this.fb.group({
      email: ['', [Validators.required,
      Validators.pattern('^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$')]],
      password: ['', Validators.required]
});

In this code, we are using the Validators module to inject input validations. In the email field, we are telling tow things.

  1. The field is required.
  2. If the format of email value should be in the same format as provided regex.

If any of the validation fails, then it will give us an error, and we will add the code that displays those errors soon.

So we have created our FormGroup model inside the component file and defined the validation for each form controls.

Step 5: Associate the FormGroup model and view.

A form group tracks the changes and status for each of its controls, so if one of the controls changes, the parent control emits the new status or value change.

Its members maintain the model for the group. After you define a model, you must update the template to reflect the model in the view.

Add the following code inside the app.component.html file.

<!-- app.component.html -->

<div class="container">
    <div class="row">
      <div class="col-md-5">
        <h1 class="page-title">Login</h1>
        <form [formGroup]="loginForm">
          <div class="form-group">
            <label for="email">Email</label>
            <input type="email"
                   class="form-control"
                   formControlName="email">
          </div>

          <div class="form-group">
            <label for="password">Password</label>
            <input type="password"
                   class="form-control"
                   formControlName ="password">
          </div>
          
          <button
          [disabled]="!loginForm.valid"
          type="submit" 
          class="btn btn-warning"
          >Sign In</button>
        </form>
      </div>
    </div>
</div>

Here you can see that the form group contains a group of controls, the loginForm FormGroup is bound to a form element with the FormGroup directive, creating the communication layer between the model and the form containing the inputs.

The formControlName input provided by a FormControlName directive binds each input to a form control defined in the FormGroup. The form controls communicate with their respective HTML elements.

Form validation in Angular 10

Form validation is used to ensure that the user input is complete and correct.

We have used the following steps to add form validation.

  1. Import the validator function in your form component.
  2. Add a validator to the field in the form.
  3. Add logic to handle the validation status.

The most common validation is any input a required field.

The next step is the button disable. We disable the button if the form is not valid. Otherwise, it will enable, and we will be able to submit the form to the server.

Right now, if you don’t write any input fields, then the button will be disabled, but if you touch any field and then go to another field, then you won’t see any error displaying. So, let’s display the errors.

Step 6: Display Angular 10 Form Validation Errors

We will write a function inside the app.component.ts file that returns true or false, and based on that, and we will display the error message.

// app.component.ts

isValidInput(fieldName): boolean {
    return this.loginForm.controls[fieldName].invalid &&
      (this.loginForm.controls[fieldName].dirty || this.loginForm.controls[fieldName].touched);
}

The function accepts fieldname as an argument and returns true or false based on the status of the form.

Now, we will use the isValidInput() function inside our HTML template.

Write the following code inside the app.component.html file.

<!-- app.component.html -->

<div class="container">
    <div class="row">
      <div class="col-md-5">
        <h1 class="page-title">Login</h1>
        <form [formGroup]="loginForm">
          <div class="form-group">
            <label for="email">Email</label>
            <input type="email"
                   class="form-control"
                   formControlName="email">
          </div>
          <div *ngIf="isValidInput('email')"
            class="alert alert-danger">
            <div *ngIf="loginForm.controls['email'].errors.required">
              Email is required.
            </div>
            <div *ngIf="loginForm.controls['email'].errors.pattern">
              Must be a valid email format.
            </div>
          </div>

          <div class="form-group">
            <label for="password">Password</label>
            <input type="password"
                   class="form-control"
                   formControlName ="password">
          </div>
          <div *ngIf="isValidInput('password')"
            class="alert alert-danger">
            <div *ngIf="loginForm.controls['password'].errors.required">
              Password is required.
            </div>
          </div>

          <button
          [disabled]="!loginForm.valid"
          type="submit" 
          class="btn btn-warning"
          >Sign In</button>
        </form>
      </div>
    </div>
</div>

Here, we are mainly checking two conditions to display the proper error.

  1. Check if there is an error at all.
  2. If there is an error, then which type of error is there.

So, first, it will check which form control value is invalid, and then it will check which kind of error is occurred. Based on the condition, it will render the validation message. See the output.

 

Angular 10 Reactive Forms

Step 9: Submit the form and log form values

The last step is to submit the form.

The FormGroup directive listens for the submit event emitted by the form element and emits a ngSubmit event that you can bind to a callback function.

Add the ngSubmit event listener to the form tag with the onSubmit() callback method.

<!-- app.component.html --> 

<form [formGroup]="loginForm" (ngSubmit)="login()">

Now, we have to define a function called login() inside the app.component.ts file.

// app.component.ts

login(): void {
    console.log(this.loginForm.value);
}

Save the file and go to the browser and fill the correct login form values and see the inspect element, you will see that both email and password values are there.

 

Angular 10 Reactive Forms with Validation

Our complete app.component.ts file looks like below.

// app.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  loginForm: FormGroup;
  constructor(private fb: FormBuilder) {
  }

  ngOnInit(): void {
    this.initForm();
  }

  initForm(): void {
    this.loginForm = this.fb.group({
      email: ['', [Validators.required,
      Validators.pattern('^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$')]],
      password: ['', Validators.required]
    });
  }

  isValidInput(fieldName): boolean {
    return this.loginForm.controls[fieldName].invalid &&
      (this.loginForm.controls[fieldName].dirty || this.loginForm.controls[fieldName].touched);
  }

  login(): void {
    console.log(this.loginForm.value);
  }
}

Inside the login() function, you can either write the direct network request code using Angular httpclient or use Angular service and call that service’s function here and pass the form values as function parameters.

So, that is it for Angular 10 Reactive Forms with Validation Example, guys. Take care.

See also

How to check Angular version

Angular 10 Tutorial

Angular Route Guard

Angular Router Navigate

Angular RouterLink

2 Comments
  1. Rodrigo Morales Quiroz says

    ERROR in src/app/accounts/login/login.component.html:5:19 – error NG8002: Can’t bind to ‘formGroup’ since it isn’t a known property of ‘form’.

    5

    Im use:

    “dependencies”: {
    “@angular/animations”: “~10.0.9”,
    “@angular/cdk”: “^10.1.3”,
    “@angular/common”: “~10.0.9”,
    “@angular/compiler”: “~10.0.9”,
    “@angular/core”: “~10.0.9”,
    “@angular/fire”: “^6.0.2”,
    “@angular/forms”: “~10.0.9”,
    “@angular/material”: “^7.3.2”,
    “@angular/platform-browser”: “~10.0.9”,
    “@angular/platform-browser-dynamic”: “~10.0.9”,
    “@angular/router”: “~10.0.9”,
    “@popperjs/core”: “^2.4.4”,
    “bootstrap”: “^4.5.2”,
    “firebase”: “^7.19.1”,
    “hammerjs”: “^2.0.8”,
    “jquery”: “^3.5.1”,
    “rxjs”: “~6.5.5”,
    “tslib”: “^2.0.0”,
    “zone.js”: “~0.10.3”
    },

    AND

    “styles”: [
    “./node_modules/bootstrap/dist/css/bootstrap.min.css”,
    “./node_modules/@angular/material/prebuilt-themes/indigo-pink.css”,
    “src/styles.css”
    ],
    “scripts”: [
    “./node_modules/jquery/dist/jquery.min.js”,
    “./node_modules/@popperjs/core/dist/umd/popper.min.js”,
    “./node_modules/bootstrap/dist/js/bootstrap.js”
    ]

    and i cant use [formGroup], i used [formsGroup] , [FormGroup] nothing.

    can y help me pls.

  2. Ram says

    Please import “FormsModule,ReactiveFormsModule” in your app.module.ts

Leave A Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.