Forms are always an integral part of our application. In angular, we build the form in 2 ways either template-driven or model-driven/reactive forms.
Here we are going to discuss reactive forms with Angular. Reactive forms are more scalable and can be managed easily. It's much simple way to validate the reactive forms. There are a number of validations which are commonly used in our application. Here we'll discuss the following validations:
- Confirm Password Validation in Angular 8
-
URL Validation in Angular 8
-
Age-Old Validation in Angular 8
-
Up to Decimal Point Validation in Angular 8
-
Number Validation in Angular 8
-
Alpha Numeric Validation in Angular 8
-
Email Id Validation in Angular 8
-
Credit Card Validation in Angular 8
Let me create a service which I'll use to validate the forms in my application: src/app/Services/validation.service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
import { AbstractControl } from '@angular/forms';
export class ValidationService {
// function to set error messages
static getValidatorErrorMessage(validatorName: string, validatorValue?: any) {
let config = {
'required': 'This field is required',
'twoDecimalAllowed': 'Decimal value upto 2 decimal places is allowed.',
'invalidNumber': 'Input should be an integer value',
'invalidCreditCard': 'Is invalid credit card number',
'invalidEmailAddress': 'Invalid email address',
'invalidPassword': 'New password and confirm password does not match',
'invalidDob': 'User must be minimum 16 Years old.',
'invalidUrl': 'Invalid URL',
'alphaNumericAllowed': 'Only apha numeric input is allowed',
'numericAllowed': 'Only numeric values are allowed',
'emailTaken': 'Email id already taken',
'minlength': `Minimum length should be ${validatorValue.requiredLength} characters`,
'maxlength': `Maximum length should be ${validatorValue.requiredLength} characters`
};
return config[validatorName];
}
static creditCardValidator(control: AbstractControl) {
// Visa, MasterCard, American Express, Diners Club, Discover, JCB
if (control.value.match(/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/)) {
return null;
} else {
return { 'invalidCreditCard': true };
}
}
static emailValidator(control: AbstractControl) {
if (control.value.length == 0 || control.value.match(/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/)) {
return null;
} else {
return { 'invalidEmailAddress': true };
}
}
static alpaNumValidator(control: AbstractControl) {
if (control.value.match(/^[a-zA-Z0-9]*$/)) {
return null;
} else {
return { 'alphaNumericAllowed': true };
}
}
static numberValidator(control: AbstractControl) {
if (control.value.length == 0 || control.value.match(/^[0-9]*$/)) {
return null;
} else {
return { 'numericAllowed': true };
}
}
static decimalValidation(control: AbstractControl) {
if (control.value.match(/^\d*\.?\d{0,2}$/g)) {
return null;
} else {
return { 'twoDecimalAllowed': true };
}
}
// function to validate that dob should be 16 years old
static dobValidator(control: AbstractControl) {
let currentDate = new Date();
if (control.value) {
let dob = new Date(control.value);
let dobYear = dob.getFullYear();
let maxDobYear = currentDate.getFullYear() - 16;
//console.log(dobYear, maxDobYear)
if (maxDobYear < dobYear) {
return { 'invalidDob': true };
}
else {
return null
}
}
}
static urlValidator(control: AbstractControl) {
const URL_REGEXP = /^(http?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|in|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/;
if (control.value.match(URL_REGEXP)) {
return null;
} else {
return { 'invalidUrl': true };
}
}
static confirmPasswordValidator(control: AbstractControl) {
const password: string = control.get('password').value; // get password from our password form control
const confirmPassword: string = control.get('confirmPassword').value; // get password from our confirmPassword form control
if (password !== confirmPassword) {
control.get('confirmPassword').setErrors({ invalidPassword: true });
}
return null
}
}
|
Now let me create a validation message component. This is the common component which will be used throughout the forms to show the validation message.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import { Component, Input } from '@angular/core';
import { FormControl } from '@angular/forms';
import { ValidationService } from 'src/app/Services/validation.service';
@Component({
selector: 'validation-messages',
template: `<div class="text-danger" *ngIf="errorMessage">{{errorMessage}}</div>`
})
export class ValidationMessagesComponent {
@Input() control: FormControl;
constructor() {
}
get errorMessage() {
for (let propertyName in this.control.errors) {
if (this.control.errors.hasOwnProperty(propertyName) && (this.control.dirty || this.control.touched)) {
return ValidationService.getValidatorErrorMessage(propertyName, this.control.errors[propertyName]);
}
}
return null;
}
}
|
I'm using validation service here in this component to call the getValidatorErrorMessage function. I'm calling this function when touching the controls or the controls are dirty.
Now we can create a component which has the registration form to show all the validation with the examples.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators, FormGroup, NgForm } from '@angular/forms';
import { ValidationService } from 'src/app/Services/validation.service';
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
form: FormGroup;
constructor(public formBuilder: FormBuilder) { }
ngOnInit() {
this.buildForm();
}
private buildForm() {
this.form = this.formBuilder.group({
'name': ['', [Validators.required, ValidationService.alpaNumValidator]],
'emailId': ['', [Validators.required, ValidationService.emailValidator]],
'dob': ['', [Validators.required, ValidationService.dobValidator]],
'phone': ['', [Validators.required, ValidationService.numberValidator, Validators.minLength(10), Validators.maxLength(10)]],
'marks': ['', [Validators.required, ValidationService.decimalValidation]],
'website': ['', [Validators.required, ValidationService.urlValidator]],
'password': ['', [Validators.required, Validators.minLength(6)]],
'confirmPassword': ['', [Validators.required]],
},
{
validator: ValidationService.confirmPasswordValidator
});
}
public save(data: NgForm) {
this.form.markAllAsTouched();
if (this.form.valid) {
console.log(data)
}
}
}
|
./Components/Users/Register/register.component.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
<div class="container">
<form [formGroup]="form">
<div class="form-group">
<label for="name"> Name</label>
<input type="text" formControlName="name" class="form-control" />
<validation-messages [control]="form.controls.name"></validation-messages>
</div>
<div class="form-group">
<label>Email Id</label>
<input type="text" formControlName="emailId" class="form-control" />
<validation-messages [control]="form.controls.emailId"></validation-messages>
</div>
<div class="form-group">
<label>Phone</label>
<input type="text" formControlName="phone" class="form-control" />
<validation-messages [control]="form.controls.phone"></validation-messages>
</div>
<div class="form-group">
<label>Marks</label>
<input type="text" formControlName="marks" class="form-control" />
<validation-messages [control]="form.controls.marks"></validation-messages>
</div>
<div class="form-group">
<label>DOB</label>
<input type="text" formControlName="dob" placeholder="2001-05-02" class="form-control" />
<validation-messages [control]="form.controls.dob"></validation-messages>
</div>
<div class="form-group">
<label>Website</label>
<input type="text" formControlName="website" placeholder="http://www.coding4developers.com"
class="form-control" />
<validation-messages [control]="form.controls.website"></validation-messages>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" formControlName="password" class="form-control" />
<validation-messages [control]="form.controls.password"></validation-messages>
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" formControlName="confirmPassword" class="form-control" />
<validation-messages [control]="form.controls.confirmPassword"></validation-messages>
</div>
<div class="form-group">
<button class="btn btn-primary" (click)="save(form.value)">
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
Register
</button>
</div>
</form>
</div>
|
After creating RegisterComponent register this component to app.module.ts also imports ReactiveFormsModule and FormsModule for using reactive form.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ValidationMessagesComponent } from './Components/Validation/validation-messages.component';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { AppRouting } from './app.routing.module';
import { RegisterComponent } from './Components/Users/Register/register.component';
@NgModule({
declarations: [
AppComponent,
RegisterComponent,
ValidationMessagesComponent
],
imports: [
BrowserModule,
AppRouting,
FormsModule,
ReactiveFormsModule
],
providers: [
],
bootstrap: [AppComponent],
entryComponents: [
ValidationMessagesComponent
]
})
export class AppModule { }
|
Here I have register ValidationMessagesComponent as an entry component because this component will have no routing. I also have imported AppRouting in app.module.ts. Here below is the routing file.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { RegisterComponent } from './Components/Users/Register/register.component';
const appRoutes: Routes = [
{ path: 'register', 'component': RegisterComponent }
];
@NgModule({
imports: [RouterModule.forRoot(appRoutes, { enableTracing: false })],
exports: [RouterModule]
})
export class AppRouting { }
|
app.component.html
1
|
<router-outlet></router-outlet>
|