Template-driven approach is used for working with simple forms. In contrast, It is used for handling more complex data. Especially when you need to work with nested values.We will create a basic form with following input fields name, email, dob and mobile number.


Define Form Structure with Ionic HTMLSet Up Ionic Project

Ionic CLI has to be installed on the development machine, and you can use the following command to install or update the tool:

npm install -g @ionic/cli
Bash

To setup a form in an Angular/Ionic app, you need to run the below command.

ionic start ionic-form-validation blank --type=angular
Bash

Get inside the project directory.

cd ionic-form-validation
Bash

Install lab mode as a dev-dependency by running the following command.

npm i @ionic/lab --save-dev
Bash

Start the Ionic app.

ionic serve -l
Bash

Ionic Forms Project

To set up a form in Ionic use Ionic form UI components, below we are creating a form for school students and a student can fill information about himself using the form. We used Ionic’s checkboxes, radio buttons, buttons and other elements to build this form.

Open home.page.html file and add the following code inside of it.

<ion-content>
  <form>
    <ion-item lines="full">
      <ion-label position="floating">Name</ion-label>
      <ion-input type="text" required></ion-input>
    </ion-item>
    <ion-item lines="full">
      <ion-label position="floating">Email</ion-label>
      <ion-input type="email" required></ion-input>
    </ion-item>
    <ion-item lines="full">
      <ion-label position="floating">DOB</ion-label>
      <ion-input type="text" required></ion-input>
    </ion-item>
    <ion-item lines="full">
      <ion-label position="floating">Mobile</ion-label>
      <ion-input type="text" required></ion-input>
    </ion-item>
    <!-- Radio buttons -->
    <ion-radio-group lines="full">
      <ion-list-header>
        <ion-label>Gender</ion-label>
      </ion-list-header>
      <ion-item>
        <ion-label>Male</ion-label>
        <ion-radio slot="start" value="male" checked></ion-radio>
      </ion-item>
      <ion-item>
        <ion-label>Female</ion-label>
        <ion-radio slot="start" value="female"></ion-radio>
      </ion-item>
    </ion-radio-group>
    <!-- Checkboxes -->
    <ion-list lines="full">
      <ion-list-header>
        <ion-label>Subjects</ion-label>
      </ion-list-header>
      <ion-item>
        <ion-label>English</ion-label>
        <ion-checkbox></ion-checkbox>
      </ion-item>
      <ion-item>
        <ion-label>Maths</ion-label>
        <ion-checkbox></ion-checkbox>
      </ion-item>
      <ion-item>
        <ion-label>Science</ion-label>
        <ion-checkbox></ion-checkbox>
      </ion-item>
      <ion-item>
        <ion-label>History</ion-label>
        <ion-checkbox></ion-checkbox>
      </ion-item>
    </ion-list>
    <ion-row>
      <ion-col>
        <ion-button type="submit" color="danger" expand="block">Submit</ion-button>
      </ion-col>
    </ion-row>
  </form>
</ion-content>
Markup

Ionic Forms Validation

Import & Register ReactiveFormsModule

To work with Reactive Forms we need to import and register ReactiveFormsModule. Now usually when we work with core Angular app so we declare ReactiveFormsModule globally in app.module.ts file. However, we have to declare ReactiveFormsModule in every page or component when we work with forms module.

Open home.module.ts and add the below code in it.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { IonicModule } from '@ionic/angular';
import { HomePage } from './home.page';
import { HomePageRoutingModule } from './home-routing.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    CommonModule,
    IonicModule,
    HomePageRoutingModule,
    FormsModule,
    ReactiveFormsModule
  ],
  declarations: [HomePage]
})
export class HomePageModule {}
TypeScript

Creating Form in Ionic with Reactive Forms

Next, we will use FormControl, FormGroup, FormBuilder, and Validators service to validate the form data.

Let’s understand what these services are?

FormGroup: A FormGroup is a collection of single or multiple FormControls and declared on the HTML’s form tag. Basically, its a collection of various form controls.

<form [formGroup]="ionicForm" (ngSubmit)="submitForm()" novalidate>
</form>
Markup

FormControl: A FormControl represents a value which is entered by the user, FormGroup is a collection of various FormControls.

<ion-content>
  <form [formGroup]="ionicForm" (ngSubmit)="submitForm()" novalidate>
    <ion-item lines="full">
      <ion-label position="floating">Name</ion-label>
      <ion-input formControlName="name" type="text" required></ion-input>
    </ion-item>
    <ion-item lines="full">
      <ion-label position="floating">Email</ion-label>
      <ion-input formControlName="email" type="email" required></ion-input>
    </ion-item>
    <ion-item lines="full">
      <ion-label position="floating">DOB</ion-label>
      <ion-datetime (ionChange)="getDate($event)" formControlName="dob" [value]="defaultDate"></ion-datetime>
    </ion-item>
    <ion-item lines="full">
      <ion-label position="floating">Mobile</ion-label>
      <ion-input formControlName="mobile" type="text" required></ion-input>
    </ion-item>
    <ion-row>
      <ion-col>
        <ion-button type="submit" color="danger" expand="block">Submit</ion-button>
      </ion-col>
    </ion-row>
  </form>
</ion-content>
Markup

FormBuilder: The FormBuilder service refers to a form object and sets up a FormGroup. It holds the user entered values and validation state of a form input field.

Import the following services to initialize the form in home.page.ts.

import { FormGroup, FormBuilder, Validators } from "@angular/forms";
TypeScript

Define the form object by declaring the FormGroup with a variable.

ionicForm: FormGroup;
TypeScript

Inject the FormBuilder service in the constructor.

constructor(public formBuilder: FormBuilder) { }
TypeScript

Setting up Date-picker in Ionic

Date-picker is used to get the date from the user, Ionic offers its own custom date-picker to deal with the date related date. We declared the date with ion-datetime tag in the HTML template. Now we will get the date value from the user and set in the dob formControl in Angular’s Reactive form.

We defined the defaultDate variable to set the default date. The getDate(e) function takes date object as an argument and convert it to YYYY-MM-DD format and set as a FormControl in the FormGroup.

getDate(e) {
   let date = new Date(e.target.value).toISOString().substring(0, 10);
   this.ionicForm.get('dob').setValue(date, {
      onlyself: true
   })
}
TypeScript

The (ngSubmit)="submitForm()" directive triggers a form submission.

submitForm() {
  console.log(this.ionicForm.value)
}
TypeScript

Enter some values in the form field and click on submit button, you will see user entered values in the ionicForm in the browser’s console.

Creating Form in Ionic

Validate Ionic Form

In this section we will learn how to validate Ionic form fields using Reactive Forms validators service.

Import Validators service to in the Ionic template, It provides built-in methods to validate form controls.

import { Validators } from "@angular/forms";
TypeScript

The Validators class offers following methods to deal with form validation in Ionic / Angular.

class Validators {
  static min(min: number): ValidatorFn
  static max(max: number): ValidatorFn
  static required(control: AbstractControl): ValidationErrors | null
  static requiredTrue(control: AbstractControl): ValidationErrors | null
  static email(control: AbstractControl): ValidationErrors | null
  static minLength(minLength: number): ValidatorFn
  static maxLength(maxLength: number): ValidatorFn
  static pattern(pattern: string | RegExp): ValidatorFn
}
TypeScript

We will trigger the validation when user clicks on the submit button, so we need to define a boolean variable and set it to false initially.

isSubmitted = false;
TypeScript

Now, we will validate our name form control. In this value we will implement required and min-length validation.

this.ionicForm = this.formBuilder.group({
   name: ['', [Validators.required, Validators.minLength(2)]],
})
TypeScript

As you can see we injected the validation methods with the help of Validators class. Validators array allow us to implement multiple validation in a single form control.

Now, we will declare the getter method to access the form control. Add the following code to access the form control directly via the Ionic / Angular template.

get errorControl() {
  return this.ionicForm.controls;
}
TypeScript

Next, we need to add the alert messages in the Ionic’s HTML template for showing the validation messages. These, messages will appear when the form is invalid.

<form [formGroup]="ionicForm" (ngSubmit)="submitForm()" novalidate>
  <ion-item lines="full">
    <ion-label position="floating">Name</ion-label>
    <ion-input formControlName="name" type="text"></ion-input>
  </ion-item>
  <!-- Error messages -->
  <span class="error ion-padding" *ngIf="isSubmitted && errorControl.name.errors?.required">
    Name is required.
  </span>
  <span class="error ion-padding" *ngIf="isSubmitted && errorControl.name.errors?.minlength">
    Name should be min 2 chars long.
  </span>
</form>
Markup

Inside the *ngIf directive, we are checking if both the conditions are true. The *ngIf="" directive will only show the alert message to the users when the form is invalid.

Following method will trigger the form on submit.

submitForm() {
  this.isSubmitted = true;
  if (!this.ionicForm.valid) {
    console.log('Please provide all the required values!')
    return false;
  } else {
    console.log(this.ionicForm.value)
  }
}
TypeScript

Here are the final code of this Ionic Angular Form validation tutorial.

home.page.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
  ionicForm: FormGroup;
  defaultDate = "1987-06-30";
  isSubmitted = false;
  constructor(public formBuilder: FormBuilder) { }
  ngOnInit() {
    this.ionicForm = this.formBuilder.group({
      name: ['', [Validators.required, Validators.minLength(2)]],
      email: ['', [Validators.required, Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$')]],
      dob: [this.defaultDate],
      mobile: ['', [Validators.required, Validators.pattern('^[0-9]+$')]]
    })
  }
  getDate(e) {
    let date = new Date(e.target.value).toISOString().substring(0, 10);
    this.ionicForm.get('dob').setValue(date, {
      onlyself: true
    })
  }
  get errorControl() {
    return this.ionicForm.controls;
  }
  submitForm() {
    this.isSubmitted = true;
    if (!this.ionicForm.valid) {
      console.log('Please provide all the required values!')
      return false;
    } else {
      console.log(this.ionicForm.value)
    }
  }
}
TypeScript
home.page.html
<ion-header>
  <ion-toolbar>
    <ion-title>Ionic Forms</ion-title>
  </ion-toolbar>
</ion-header>
<ion-content>
  <form [formGroup]="ionicForm" (ngSubmit)="submitForm()" novalidate>
    <ion-item lines="full">
      <ion-label position="floating">Name</ion-label>
      <ion-input formControlName="name" type="text"></ion-input>
    </ion-item>
    <span class="error ion-padding" *ngIf="isSubmitted && errorControl.name.errors?.required">
      Name is required.
    </span>
    <span class="error ion-padding" *ngIf="isSubmitted && errorControl.name.errors?.minlength">
      Name should be min 2 chars long.
    </span>
    <ion-item lines="full">
      <ion-label position="floating">Email</ion-label>
      <ion-input formControlName="email" type="email"></ion-input>
    </ion-item>
    <span class="error ion-padding" *ngIf="isSubmitted && errorControl.email.errors?.required">
      Email is required.
    </span>
    <span class="error ion-padding" *ngIf="isSubmitted && errorControl.email.errors?.pattern">
      Please provide valid email id.
    </span>
    <ion-item lines="full">
      <ion-label position="floating">DOB</ion-label>
      <ion-datetime (ionChange)="getDate($event)" formControlName="dob" [value]="defaultDate"></ion-datetime>
    </ion-item>
    <ion-item lines="full">
      <ion-label position="floating">Mobile</ion-label>
      <ion-input maxlength="10" formControlName="mobile" type="text" required></ion-input>
    </ion-item>
    <span class="error ion-padding" *ngIf="isSubmitted && errorControl.mobile.errors?.required">
      Mobile number is required.
    </span>
    <span class="error ion-padding" *ngIf="isSubmitted && errorControl.mobile.errors?.pattern">
      Only numerical values allowed.
    </span>
    <ion-row>
      <ion-col>
        <ion-button type="submit" color="danger" expand="block">Submit</ion-button>
      </ion-col>
    </ion-row>
  </form>
</ion-content>
Markup

Validate Ionic Form

Conclusion

Finally, we have finished Ionic Angular Form Validation tutorial using reactive forms.

We just learned the basic form validation with Reactive Forms in Ionic app, I hope you will surely liked it.