In this tutorial, I will show you how to implement Angular Template Driven Forms Validation example (and Submit) with Angular 16 and Bootstrap 4.
More Practice:
– Angular 16 Form Validation example (Reactive Forms)
– Angular 16 File upload example with progress bar
– Angular 16 CRUD example with Web API
– Angular 16 JWT Authentication & Authorization example
Serverless with Firebase:
– Angular 16 Firebase CRUD example
– Angular 16 Firestore CRUD example
– Angular 16 File Upload with Firebase Storage
Contents
- Angular 16 Template Driven Forms Validation overview
- Technology
- Setup Project
- Import Bootstrap
- Template Driven Forms Validation with Angular 16
- Angular 16 component with Template Driven Form
- Angular Template Driven Form Validation template
- Confirm Password validation in Template Driven Form
- Run Template Driven Form Validation with Angular 16 example
- Conclusion
- Further Reading
Angular 16 Template Driven Forms Validation overview
We will implement validation for a Angular Form using Template Driven Forms and Bootstrap 4. The form has:
- Full Name: required
- Username: required, from 6 to 20 characters
- Email: required, email format
- Password: required, from 6 to 40 characters
- Confirm Password: required, same as Password
- Accept Terms Checkbox: required
Some fields could be wrong:
Successful Submission will look like this:
Technology
We’re gonna use following modules:
- Angular 16
- Bootstrap 4
- @angular/forms 16
Setup Project
First we need to add the FormsModule
into our App Module.
Open src/app/app.module.ts and import FormsModule
from @angular/forms
:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Import Bootstrap
Open src/index.html and add following line to <head>
tag:
<!doctype html>
<html lang="en">
<head>
...
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" />
</head>
<body>
<app-root></app-root>
</body>
</html>
Another way to import Bootstrap into Angular project:
– Run the command: npm install [email protected]
.
– Next, open src/style.css and add following code:
@import "~bootstrap/dist/css/bootstrap.css";
Template Driven Forms Validation with Angular 16
Template Driven Forms rely on directives defined in the FormsModule. In this example, we will use:
NgModel
NgForm
: creates a top-levelFormGroup
instance, binds it to a<form>
element to track form value and validation status.
We also need to use attributes of following FormsModule
directives:
RequiredValidator
: requiredMinLengthValidator
: minlengthMaxLengthValidator
: maxlengthEmailValidator
: email
To get access to the NgForm
and the overall form status, we declare a template reference variable #f="ngForm"
.
<form
name="form"
#f="ngForm"
(ngSubmit)="f.form.valid && onSubmit()"
>
The f
template variable is now a reference to the NgForm
directive instance. So we can use f.form.valid
or f.submitted
for example.
Similarly, to inspect the properties of the associated FormControl
, we export the directive into a local template variable using ngModel
as the key (#username="ngModel"
).
<input
type="text"
class="form-control"
name="username"
[(ngModel)]="form.username"
required
minlength="6"
maxlength="20"
#username="ngModel"
/>
Now we can access the control using the directive’s control property: username.errors
.
<div *ngIf="f.submitted && username.errors" class="invalid-feedback">
<div *ngIf="username.errors['required']">Username is required</div>
<div *ngIf="username.errors['minlength']">
Username must be at least 6 characters
</div>
<div *ngIf="username.errors['maxlength']">
Username must be at most 20 characters
</div>
</div>
Angular 16 component with Template Driven Form
In the component that working with Template Driven Form, let’s create an object (form
) that stores all form value. We will bind the form fields with the property of this object.
Then create two functions for Form submission and Form reset: onSubmit()
and onReset()
.
app/app.component.ts
import { Component } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
form = {
fullname: '',
username: '',
email: '',
password: '',
confirmPassword: '',
acceptTerms: false,
};
onSubmit(): void {
console.log(JSON.stringify(this.form, null, 2));
}
onReset(form: NgForm): void {
form.reset();
}
}
Angular Template Driven Form Validation template
Now we create the form with input fields and validation messages.
We bind to the FormGroup
object (form
) in the app component and use f
as template variable. Form submit event will call onSubmit()
handler above using event binding (ngSubmit)
.
Validation messages will display after form submission for the first time by f.submitted
value.
app/app.component.html
<div class="register-form">
<form
name="form"
#f="ngForm"
(ngSubmit)="f.form.valid && onSubmit()"
novalidate
[appMatchPassword]="['password', 'confirmPassword']"
>
<div class="form-group">
<label>Full Name</label>
<input
type="text"
class="form-control"
name="fullname"
[(ngModel)]="form.fullname"
required
#fullname="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && fullname.errors }"
/>
<div *ngIf="f.submitted && fullname.errors" class="invalid-feedback">
<div *ngIf="fullname.errors['required']">Fullname is required</div>
</div>
</div>
<div class="form-group">
<label>Username</label>
<input
type="text"
class="form-control"
name="username"
[(ngModel)]="form.username"
required
minlength="6"
maxlength="20"
#username="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && username.errors }"
/>
<div *ngIf="f.submitted && username.errors" class="invalid-feedback">
<div *ngIf="username.errors['required']">Username is required</div>
<div *ngIf="username.errors['minlength']">
Username must be at least 6 characters
</div>
<div *ngIf="username.errors['maxlength']">
Username must be at most 20 characters
</div>
</div>
</div>
<div class="form-group">
<label>Email</label>
<input
type="email"
class="form-control"
name="email"
[(ngModel)]="form.email"
required
email
#email="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && email.errors }"
/>
<div *ngIf="f.submitted && email.errors" class="invalid-feedback">
<div *ngIf="email.errors['required']">Email is required</div>
<div *ngIf="email.errors['email']">Email is invalid</div>
</div>
</div>
<div class="form-group">
<label>Password</label>
<input
type="password"
class="form-control"
name="password"
[(ngModel)]="form.password"
required
minlength="6"
maxlength="40"
#password="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && password.errors }"
/>
<div *ngIf="f.submitted && password.errors" class="invalid-feedback">
<div *ngIf="password.errors['required']">Password is required</div>
<div *ngIf="password.errors['minlength']">
Password must be at least 6 characters
</div>
<div *ngIf="password.errors['maxlength']">
Username must not exceed 40 characters
</div>
</div>
</div>
<div class="form-group">
<label>Confirm Password</label>
<input
type="password"
class="form-control"
name="confirmPassword"
[(ngModel)]="form.confirmPassword"
required
#confirmPassword="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && confirmPassword.errors }"
/>
<div
*ngIf="f.submitted && confirmPassword.errors"
class="invalid-feedback"
>
<div *ngIf="confirmPassword.errors['required']">
Confirm Password is required
</div>
<div *ngIf="confirmPassword.errors['matching']">
Confirm Password does not match
</div>
</div>
</div>
<div class="form-group form-check">
<input
type="checkbox"
lass="form-control"
name="acceptTerms"
[(ngModel)]="form.acceptTerms"
class="form-check-input"
required
#acceptTerms="ngModel"
[ngClass]="{ 'is-invalid': f.submitted && acceptTerms.errors }"
/>
<label for="acceptTerms" class="form-check-label">
I have read and agree to the Terms
</label>
<div *ngIf="f.submitted && acceptTerms.errors" class="invalid-feedback">
Accept Terms is required
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Register</button>
<button
type="button"
(click)="onReset(f)"
class="btn btn-warning float-right"
>
Reset
</button>
</div>
</form>
</div>
You can see that we has appMatchPassword
directive in the form: [appMatchPassword]="['password', 'confirmPassword']"
. Let’s continue to the next section for more details.
Confirm Password validation in Template Driven Form
Now we will create Validation class to implement password and confirm password validation.
– First, the validator returns null
(meaning validation has passed) if there is any error on the control that we want to check (confirm password).
– Next, the validator checks that two fields match or not and set error (matching
property value to true
) on checking control if validation fails.
utils/validation.ts
import { FormGroup } from '@angular/forms';
export default class Validation {
static match(controlName: string, checkControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const checkControl = formGroup.controls[checkControlName];
if (checkControl?.errors && !checkControl.errors['matching']) {
return null;
}
if (control?.value !== checkControl?.value) {
checkControl?.setErrors({ matching: true });
return { matching: true };
} else {
checkControl?.setErrors(null);
return null;
}
};
}
}
Then we create a custom Directive to implement custom validator for the Template Driven Form.
Run the command: ng g d directives/passwordPattern
You will see a folder named directives is created with two files inside it: match-password.directive.ts and match-password.directive.spec.ts.
We will implement the Validator
interface on MatchPasswordDirective
class and override the validate()
method. This directive is used to validate if the password
and confirmPassword
are matching or not.
Open directives/match-password.directive.ts and write following code:
import { Directive, Input } from '@angular/core';
import { FormGroup, NG_VALIDATORS, ValidationErrors, Validator } from '@angular/forms';
import Validation from '../utils/validation';
@Directive({
selector: '[appMatchPassword]',
providers: [{ provide: NG_VALIDATORS, useExisting: MatchPasswordDirective, multi: true }]
})
export class MatchPasswordDirective implements Validator {
@Input('appMatchPassword') matchPassword: string[] = [];
validate(formGroup: FormGroup): ValidationErrors | null {
return Validation.match(this.matchPassword[0], this.matchPassword[1])(formGroup);
}
}
The input is an array of Strings, which contains 2 fields to match. In the validate()
method, we call Validation.match()
static method.
Run Template Driven Form Validation with Angular 16 example
You can run our App with command: ng serve
.
If the process is successful, open Browser with Url: http://localhost:4200/
and check it.
Or run on Stackblitz:
Conclusion
Today we’ve built Angular 16 Template Driven Forms Validation example successfully with Angular Forms module & Bootstrap 4.
You can also use the Form Validation in following posts:
– Angular 16 File upload example with progress bar
– Angular 16 CRUD example with Web API
– Angular 16 JWT Authentication example with Web Api
Or using Angular Reactive Forms Module:
Angular 16 Form Validation example (Reactive Forms)
Happy learning! See you again.
Further Reading
Serverless with Firebase:
– Angular 16 Firebase CRUD example
– Angular 16 Firestore CRUD example
– Angular 16 File Upload with Firebase Storage
Fullstack CRUD Application:
– Angular 16 + Node Express + MySQL example
– Angular 16 + Node Express + PostgreSQL example
– Angular 16 + Node Express + MongoDB example
– Angular 16 + Spring Boot + H2 example
– Angular 16 + Spring Boot + MySQL example
– Angular 16 + Spring Boot + PostgreSQL example
– Angular 16 + Spring Boot + MongoDB example
– Angular + Django example
– Angular + Django + MySQL example
– Angular + Django + PostgreSQL example
– Angular + Django + MongoDB example