Creating a Custom Validation Message Framework in Angular (2024)

Table of Contents
Creating the Directive Structure

In this article, we’ll explore how to build a custom validation message framework for Angular forms. By leveraging a directive and a messages.json file, we can streamline error handling and enhance the user experience.

Creating a Custom Validation Message Framework in Angular (2)
Creating a Custom Validation Message Framework in Angular (3)

Traditionally, developers manually wrote error messages for each input field in reactive forms. This approach led to repetitive code and maintenance challenges. Our goal is to simplify this process and make it more efficient.

 <mat-form-field class="example-full-width">
<mat-label>Location</mat-label>
<input matInput formControlName="location">
<mat-error *ngIf="userAddressValidations.get('location').hasError('required')">
<mat-icon aria-hidden="false" aria-label="Example home icon" fontIcon="home"></mat-icon>Please fill out this field.
</mat-error>
<mat-error *ngIf="userAddressValidations.get('location').hasError('minlength')">
Minimum 4 characters required.
</mat-error>
<mat-error *ngIf="userAddressValidations.get('location').hasError('maxlength')">
Accepts only 20 characters.
</mat-error>
</mat-form-field>

By using a directive and messages.json file the above problem code can be reduced to the following code.

<mat-form-field class="example-full-width">
<mat-label>Last Name</mat-label>
<input matInput formControlName="lastName" appFormValidationMsg>
</mat-form-field>

The below code is for displaying custom error message .

validationMsgId value needs to be passed to validation directive.

<mat-form-field class="example-full-width">
<input matInput formControlName="firstName" appFormValidationMsg [validationMsgId]="'firstName'" placeholder="First Name">

</mat-form-field>

The below code is for Onblur validation.

The blurFlg value (True) needs to be passed to Validation directive. The validation framework considers the form control as on blur and the validation error message is displayed when the focus goes away from the field. Next time It executes regular validation instead of onblur behaviour

 <mat-form-field class="example-full-width">
<mat-label>Blur Flag</mat-label>
<input matInput formControlName="middleName" appFormValidationMsg [blurFlag]="true">
</mat-form-field>

Creating the Directive

To create our custom validation message framework, we’ll start by designing a directive. This directive will automatically handle validation messages based on the form control’s state. Here’s how you can create it:

The below code is for field validation- FormValidationMsgDirective.ts

import {
Directive,
ElementRef,
HostListener,
Input,
OnDestroy,
OnInit
} from '@angular/core';
import {FormControl, NgControl, ValidationErrors} from "@angular/forms";
import {Subscription} from "rxjs";
import {MatIconRegistry} from "@angular/material/icon";
import {DomSanitizer} from "@angular/platform-browser";
import Message from "../../assets/messages.json";

@Directive({
selector: '[appFormValidationMsg]'
})
export class FormValidationMsgDirective implements OnInit,OnDestroy{

constructor(private elRef: ElementRef,
private control: NgControl,
private matIconRegistry:MatIconRegistry,
private domSanitizer: DomSanitizer
) { }

@Input() validationMsgId: string ;
@Input() blurFlag: boolean = false;
errorSpanId: string='';
statusChangeSubscription: Subscription;

ngOnInit(): void {
this.errorSpanId = String(this.control?.name)+"-"+Math.random() + '-error-msg';
if(!this.blurFlag) {
this.formControlStatusChange();
}
}

formControlStatusChange(){
this.statusChangeSubscription = this.control?.statusChanges.subscribe(
(status) => { status == 'INVALID' ? this.showError() : this.removeError(); }
)
}

@HostListener('blur',["$event"])
handleBlurEvent(event){
if (this.control.value == null || this.control.value == '') {
this.control.errors ? this.showError() : this.removeError();
}
if(this.blurFlag){
this.formControlStatusChange();
this.control.control.markAsTouched({onlySelf:false})
this.getFormControl().updateValueAndValidity({onlySelf:false,emitEvent:true})
this.blurFlag = false;
}
}

getFormControl(): FormControl {
return this.control?.control as FormControl;
}

public showError() {
this.removeError();
const valErrors: ValidationErrors = this.control.errors;
const errorMsg = this.getMessageKey(Object.entries(valErrors)[0]);
const errSpan = '<div style="color:#DB3321;margin-top: -14px;" id="' + this.errorSpanId + '">' +
'<img alt="error-icon" src="./assets/error.png" width="16px" height="16px" style="margin-bottom: -2px; padding-right: 8px">' + errorMsg + '</div>';
const errRadioSpan = '<div style="color:#DB3321" id="' + this.errorSpanId + '">' +
'<img alt="error-icon" src="./assets/error-f--xs.svg" width="16px" height="16px" style="margin-bottom: -2px; padding-right: 8px">' + errorMsg + '</div>';
this.domSanitizer.bypassSecurityTrustHtml(errSpan);
this.domSanitizer.bypassSecurityTrustHtml(errRadioSpan);
const closestMatFormField = this.elRef.nativeElement.closest('mat-form-field');
const closestMatRadioGroup = this.elRef.nativeElement.closest('mat-radio-group');
if(closestMatFormField){
closestMatFormField.insertAdjacentHTML('beforeend',errSpan);
}else if(closestMatRadioGroup){
closestMatRadioGroup.insertAdjacentHTML('afterend',errRadioSpan);
}
}
public removeError() {
const errorElement = document.getElementById(this.errorSpanId);
if(errorElement) errorElement.remove();
}

public getMessageKey(validationError:any){

let errorMessageKey = validationError[0]+ '-msg';
if(this.validationMsgId){
errorMessageKey = this.validationMsgId + '-' + errorMessageKey
}

return Message[errorMessageKey]?.replace("%s",String(validationError[1]?.requiredLength)?.trim());
}
ngOnDestroy() {
this.statusChangeSubscription?.unsubscribe();
}
}

The below code is for form submit validation.

FormSubmitValidationMsgDirective.ts

import { Directive, Input, HostListener } from '@angular/core';
import {FormGroup, Validators} from '@angular/forms';
@Directive({
selector: '[appFormSubmitValidationMsg]'
})
export class FormSubmitValidationMsgDirective {

@Input() validationControl: FormGroup;

@HostListener('click', ["$event"])
handleClickEvent(event) {
this.markAsTouched(this.validationControl);
return false;
}
public markAsTouched(formGroup: FormGroup): void {

(<any>Object).values(formGroup.controls).forEach( control => {

if(control.hasValidator(Validators.required) && !control.value){
control.markAsTouched() ;
control.updateValueAndValidity({ onlySelf: false, emitEvent: true });
}
if (control?.controls) {
this.markAsTouched(control);
}
})
}

}

Structure

The messages.json file should contain a mapping of error keys to actual error messages. For example:

{

"required-msg": "This field is required.",
"firstName-required-msg": "The first name is required.",
"maxlength-msg": "%s character limit exceeded.",
"firstName-maxlength-msg": "%s character limit exceeded.",
"minlength-msg":"Must be %s numeric digits.",
"firstName-minlength-msg":"Must be %s numeric digits."
"customMsgId-minlength-msg":"Must be %s numeric digits."
}

Our framework automatically displays validation messages when a form control’s value changes. Here’s how it works:

  1. First-Time Display: The blurFlag ensures that validation messages appear only after the user interacts with the input field.
  2. Subsequent Typing: Once the user starts typing, validation messages appear dynamically based on the input value.

Let’s walk through the steps to implement our custom validation message framework:

  1. Setting Up the Directive: Add the ValidationMessagesDirective to your Angular project.
  2. Creating the messages.json File: Store it in a central location (e.g., assets folder) and load it during app initialization.
  3. Integrating with Form Controls: Apply the directive to form controls by binding the messages input.

Our custom validation message framework simplifies error handling, improves maintainability, and enhances the user experience. By following these steps, you can create a reusable solution for your Angular projects.

GitHub: https://github.com/SwamyKallem/validation_error_angular_framework

Creating a Custom Validation Message Framework in Angular (2024)
Top Articles
What are liquidity pools in decentralized finance (DeFi)?
Wealth management for families through different life cycles | HSBC China
Best Pizza Novato
Garrison Blacksmith Bench
CLI Book 3: Cisco Secure Firewall ASA VPN CLI Configuration Guide, 9.22 - General VPN Parameters [Cisco Secure Firewall ASA]
Chalupp's Pizza Taos Menu
Santa Clara College Confidential
Elden Ring Dex/Int Build
Citi Card Thomas Rhett Presale
Rainfall Map Oklahoma
Craigslist Heavy Equipment Knoxville Tennessee
Sport Clip Hours
Immediate Action Pathfinder
Mlb Ballpark Pal
Colts seventh rotation of thin secondary raises concerns on roster evaluation
RBT Exam: What to Expect
Playgirl Magazine Cover Template Free
How to find cash from balance sheet?
"Une héroïne" : les funérailles de Rebecca Cheptegei, athlète olympique immolée par son compagnon | TF1 INFO
Comics Valley In Hindi
Transactions (zipForm Edition) | Lone Wolf | Real Estate Forms Software
Tyrone Unblocked Games Bitlife
Horn Rank
Southwest Flight 238
Hannah Palmer Listal
Breckiehill Shower Cucumber
Snohomish Hairmasters
WRMJ.COM
Arlington Museum of Art to show shining, shimmering, splendid costumes from Disney Archives
Horses For Sale In Tn Craigslist
1964 Impala For Sale Craigslist
Publix Coral Way And 147
Gridwords Factoring 1 Answers Pdf
MethStreams Live | BoxingStreams
Human Unitec International Inc (HMNU) Stock Price History Chart & Technical Analysis Graph - TipRanks.com
Ultra Clear Epoxy Instructions
Aveda Caramel Toner Formula
Babylon 2022 Showtimes Near Cinemark Downey And Xd
8 Ball Pool Unblocked Cool Math Games
Final Jeopardy July 25 2023
Union Corners Obgyn
Jetblue 1919
Busted Newspaper Mcpherson Kansas
Mathews Vertix Mod Chart
Academic Calendar / Academics / Home
Bekkenpijn: oorzaken en symptomen van pijn in het bekken
Anonib New
F9 2385
Grace Charis Shagmag
King Fields Mortuary
Philasd Zimbra
Latest Posts
Article information

Author: Pres. Carey Rath

Last Updated:

Views: 5758

Rating: 4 / 5 (41 voted)

Reviews: 88% of readers found this page helpful

Author information

Name: Pres. Carey Rath

Birthday: 1997-03-06

Address: 14955 Ledner Trail, East Rodrickfort, NE 85127-8369

Phone: +18682428114917

Job: National Technology Representative

Hobby: Sand art, Drama, Web surfing, Cycling, Brazilian jiu-jitsu, Leather crafting, Creative writing

Introduction: My name is Pres. Carey Rath, I am a faithful, funny, vast, joyous, lively, brave, glamorous person who loves writing and wants to share my knowledge and understanding with you.