ANGULAR
Complete Angular Tutorial For Beginners Introduction to Angular | What is Angular? Architecture Overview & Concepts of Angular How to Install Angular How to Create a new project in Angular Bootstrapping in Angular: How It Works Internally Angular Components Overview & Examples Data Binding in Angular Interpolation in Angular Property Binding in Angular Event Binding in Angular ngModel & Two way Data binding in Angular NgModelChange & Change Event in Angular Child/Nested Components in Angular angular directives angular ngFor directive ngSwitch, ngSwitchcase, ngSwitchDefa ult Angular Example How to use ngIf, else, then in Angular By example NgClass Example Conditionally apply class Angular ngStyle Directive Angular Trackby to improve ngFor Performance How to Create & Use Custom Directive In Angular Working with Angular Pipes How to Create Custom Pipe in Angular Formatting Dates with Angular Date Pipe Using Angular Async Pipe with ngIf & ngFor angular keyValue pipe Using Angular Pipes in Components or Services Angular Component Communication & Sharing Data Angular Pass data to child component Angular Pass data from Child to parent component Component Life Cycle Hooks in Angular Angular ngOnInit And ngOnDestroy Life Cycle hook Angular ngOnChanges life Cycle Hook Angular ngDoCheck Life Cycle Hook Angular Forms Tutorial: Fundamentals & Concep t s Angular Template-driven forms example How to set value in template-driven forms in Angular Angular Reactive Forms Example Using Angular FormBuilder to build Forms SetValue & PatchValue in Angular StatusChanges in Angular Forms ValueChanges in Angular Forms FormControl in Angular FormGroup in Angular Angular FormArray Example Nested FormArray Example Add Form Fields Dynamically SetValue & PatchValue in FormArray Angular Select Options Example in Angular Introduction to Angular Services Introduction to Angular Dependency Injection Angular Injector, @Injectable & @Inject Angular Providers: useClass, useValue, useFactory & useExisting Injection Token in Angular How Dependency Injection & Resolution Works in Angular Angular Singleton Service ProvidedIn root, any & platform in Angular @Self, @SkipSelf & @Optional Decorators Angular '@Host Decorator in Angular ViewProviders in Angular Angular Reactive Forms Validation Custom Validator in Angular Reactive Form Custom Validator with Parameters in Angular Inject Service Into Validator in Angular template_driven_form_validation_in_angular Custom Validator in Template Driven Forms in Angular Angular Async Validator Example Cross Field or Multi Field Validation Angular How to add Validators Dynamically using SetValidators in Angular Angular HttpClient Tutorial & Example Angular HTTP GET Example using httpclient Angular HTTP POST Example URL Parameters, Query Parameters, httpparams in Angular HttpClient Angular HTTPHeaders Example Understanding HTTP Interceptors in Angular Angular Routing Tutorial with Example Location Strategy in Angular Angular Route Params Angular : Child Routes / Nested Route Query Parameters in Angular Angular Pass Data to Route: Dynamic/Static RouterLink, Navigate & NavigateByUrl to Navigate Routes RouterLinkActive in Angular Angular Router Events ActivatedRoute in Angular Angular Guards Tutorial Angular CanActivate Guard Example Angular CanActivateChild Example Angular CanDeactivate Guard Angular Resolve Guard Introduction to Angular Modules or ngModule Angular Routing between modules Angular Folder Structure Best Practices Guide to Lazy loading in Angular Angular Preloading Strategy Angular CanLoad Guard Example Ng-Content & Content Projection in Angular Angular @input, @output & EventEmitter Template Reference Variable in Angular ng-container in Angular How to use ng-template & TemplateRef in Angular How to Use ngTemplateOutlet in Angular '@Hostbinding and @Hostlistener_in_Angular Understanding ViewChild, ViewChildren &erylist in Angular ElementRef in Angular Renderer2 Example: Manipulating DOM in Angular ContentChild and ContentChildren in Angular AfterViewInit, AfterViewChecked, AfterContentInit & AfterContentChecked in Angular Angular Decorators Observable in Angular using RxJs Create observable from a string, array & object in angular Create Observable from Event using FromEvent in Angular Using Angular observable pipe with example Angular Map Operator: Usage and Examples Filter Operator in Angular Observable Tap operator in Angular observable Using SwitchMap in Angular Using MergeMap in Angular Using concatMap in Angular Using ExhaustMap in Angular Take, TakeUntil, TakeWhile & TakeLast in Angular Observable First, Last & Single Operator in Angular Observable Skip, SkipUntil, SkipWhile & SkipLast Operators in Angular The Scan & Reduce operators in Angular DebounceTime & Debounce in Angular Delay & DelayWhen in Angular Using ThrowError in Angular Observable Using Catcherror Operator in Angular Observable ReTryWhen inReTry, ReTryWhen in Angular Observable Unsubscribing from an Observable in Angular Subjects in Angular ReplaySubject, BehaviorSubject & AsyncSubject in Angular Angular Observable Subject Example Sharing Data Between Components Angular Global CSS styles View Encapsulation in Angular Style binding in Angular Class Binding in Angular Angular Component Styles How to Install & Use Angular FontAwesome How to Add Bootstrap to Angular Angular Location Service: go/back/forward Angular How to use APP_INITIALIZER Angular Runtime Configuration Angular Environment Variables Error Handling in Angular Applications Angular HTTP Error Handling Angular CLI tutorial ng new in Angular CLI How to update Angular to latest version Migrate to Standalone Components in Angular Create Multiple Angular Apps in One Project Set Page Title Using Title Service Angular Example Dynamic Page Title based on Route in Angular Meta service in Angular. Add/Update Meta Tags Example Dynamic Meta Tags in Angular Angular Canonical URL Lazy Load Images in Angular Server Side Rendering Using Angular Universal The requested URL was not found on this server error in Angular Angular Examples & Sample Projects Best Resources to Learn Angular Best Angular Books in 2020

Custom Validator in Template Driven Forms in Angular

Learn how to build custom validator in template-driven forms. In Angular, we have two API to build Angular Forms. They are Reactive Forms and template-driven forms. In template-driven forms, we define validation rule as an HTML attribute in the HTML markup. The Angular provides a few built-in Validation attributes out of the box. In this tutorial, we will talk about how to build a custom validation attribute using Angular Directive. We also show you how to pass a parameter & how to inject service into the validation attribute.

Custom Validator in Template Driven Forms

Create a new Angular Project. Copy the following code to app.component.ts

                              

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent {
 
  constructor() {
  }
 
}
 
                            
                        

Copy the following code app.component.html

                              
 
<h1>Custom Validator in Template driven forms</h1>
 
<h2>Template Form</h2>
 
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm)" novalidate>
 
  <label for="numVal">Number :</label>
  <input type="text" name="numVal" ngModel #numVal="ngModel"> 
 
  <p>Is Form Valid : {{myForm.valid}} </p>
 
  <p>Form  : {{ myForm.value | json}} </p>
  <p>
    <button type="submit" [disabled]="!myForm.valid">Submit</button>
  </p> 
 
</form>
                            
                        

It has only one input field numVal. Let us create a validator to ensure that the value of the numVal is greater than 10.

Built-in Validators

The Angular Forms Module already has a few built-in validators. They are listed below. But we do not have a greater than validator.

  1. Required validator
  2. Min length Validator
  3. Max length Validator
  4. Pattern Validator
  5. Email Validator

How to Build Custom Validator in template-driven form

Building a Validator in template-driven forms is similar to building an Angular directive. The directive must implement the Validator interface.

Validator Interface

                              
 
interface Validator {
  validate(control: AbstractControl): ValidationErrors | null
  registerOnValidatorChange(fn: () => void)?: void
}
 
                            
                        

The directive must implement the validate function. Notice that the validate function has the same signature as the ValidatorFn Interface. Whenever the Validator directive is invoked angular looks for the validate method and invokes it.

Validate Function

A Validator is just a function, which must implement ValidatorFn Interface.

                              

interface ValidatorFn {
  (control: AbstractControl): ValidationErrors | null
}
 
                            
                        

The function takes the AbstractControl. This is the base class for FormControl, FormGroup, and FormArray. The validator function must return a list of errors i.e ValidationErrors or null if the validation has passed

Custom Validator Example

Create the gte.validator.ts and copy the following code.

                              


import { Validator, NG_VALIDATORS, FormControl } from '@angular/forms'
import { Directive, OnInit, forwardRef } from '@angular/core';
 
 
@Directive({
  selector: '[gteValidator]',
  providers: [
    { provide: NG_VALIDATORS, useExisting: gteValidatorDirective, multi: true }
  ]
})
export class gteValidatorDirective implements Validator, OnInit {
 
  ngOnInit() {
  }
 
  validate(c: FormControl) {
 
    let v: number = +c.value;
 
    if (isNaN(v)) {
      return { 'gte': true, 'requiredValue': 10 }
    }
 
    if (v <= +10) {
      return { 'gte': true, 'requiredValue': 10 }
    }
 
    return null;
  }
}
 
                            
                        

We decorate the directive using @Directive decorator.

We use the directive as an attribute in the HTML template. The attribute needs a name or selector. We assign the name as gteValidator in the selector metadata section of the directive decorator.

                              

selector: '[gteValidator]',
                            
                        

The Angular knows nothing about the Validation capabilities of our directive. Hence we need to register it in Angular Providers metadata using the special injection token NG_VALIDATORS. We also set multi:true because there can be more validation directives.

                              

{ provide: NG_VALIDATORS, useExisting: gteValidatorDirective, multi: true }
                            
                        

The directive class must implement the validate method. The validate method must honor the ValidatorFn Interface.

                              
 
  validate(c: FormControl) {
 
    let v: number = +c.value;
 
    if (isNaN(v)) {
      return { 'gte': true, 'requiredValue': 10 }
    }
 
    if (v <= +10) {
      return { 'gte': true, 'requiredValue': 10 }
    }
 
    return null;
  }
 
                            
                        

It is a simple function, which checks if the value is a number and is less than 10. It returns null if it passes all checks.

If Validation fails it returns the ValidationErrors. It is a key-value pair object of type [key: string]: any and it defines the broken rule. The key is the string and should contain the name of the broken rule. The value can be anything, but usually set to true.

We return the following key-value pair when the validation fails

                              

return { 'gte': true, 'requiredValue': 10 }
                            
                        

The 'gte': true: indicates that the validation has failed. 'requiredValue': 10 is used by the template to display that the expected value is greater than 10.

Using the Custom Validator

Since this is a template-driven form., we do not have to do anything in the component class. In the HTML template just add the attribute gteValidator as shown below

                              
 
  <label for="numVal">Number :</label>
 
  <input type="text" name="numVal" ngModel #numVal="ngModel" gteValidator> 
 
  <div *ngIf="!numVal.valid && (numVal.dirty ||numVal.touched)">
    <div *ngIf="numVal.errors.gte">
      The number should be greater than {{numVal.errors.requiredValue}}
    </div>
  </div>
 
                            
                        

Validators return ValidationErrors. They are added to the control’s errors collection of the control. The valid property of the control is set to false.

Hence we check if the valid property. We also check the dirty and touched property. Because we do not want to display the error message when the form is displayed for the first time.

We check if the gte is true and display the error message. Note that gte is the name of the key we used while creating the validator.

We also make use of requiredValue to show a meaningful message to the user.

                              

    <div *ngIf="numVal.errors.gte">
      The number should be greater than {{numVal.errors.requiredValue}}
    </div>
 
                            
                        

Passing Parameter to Validator

We have hardcoded the value of 10 in the above example. This will make our validator difficult to reuse. If we want to resue it, we need to pass the number to be checked as the parameter.

Since they are directives, we can use Input decorator to pass the parameter to the Validator.

Open the template add the special attribute gteNum="20"

                              
 
<input type="text" name="numVal" ngModel #numVal="ngModel" gteValidator gteNum="20" > 
 
                            
                        

You can read the gteNum from the template using the Input decorator as shown below

                              

@Input,("gteNum") gteNum:number
 
                            
                        

Now, you can remove the hardcoded value 10 and use the gteNum instead

The complete validator code is as shown below.

                              

import { Validator, NG_VALIDATORS, FormControl } from '@angular/forms'
import { Directive,  Input } from '@angular/core';
 
@Directive,({
  selector: '[gteValidator]',
  providers: [
    { provide: NG_VALIDATORS, useExisting: gteValidatorDirective, multi: true }
  ]
})
export class gteValidatorDirective implements Validator {
 
  @Input,("gteNum") gteNum:number
 
  validate(c: FormControl) {
 
    let v: number = +c.value;
 
    if (isNaN(v)) {
      return { 'gte': true, 'requiredValue': this.gteNum }
    }
 
    if (v <= +this.gteNum) {
      return { 'gte': true, 'requiredValue': this.gteNum }
    }
 
    return null;
  }
 
}
 
                            
                        

Injecting Service into Validator

The validator may depend on some external service to validate the value. For Example, it may need to fetch data from the back end server.

Let us move the validation logic in the above validator to a separate service. Create a service gte.service.ts and copy the following code

                              


import { Injectable } from '@angular/core';
 
@Injectable({
  providedIn: 'root',
})
export class gteService {
 
  gte(num:any, requiredValue:Number) : Boolean {
 
    if (isNaN(num)) {
      return false;
    }      
  
    if (num <= +requiredValue) {
      return false;
    }
 
    return true;
  }
}
 
                            
                        

In the validation directive, create a constructor method and inject the service. The complete code is as shown below

                              

 
import { Validator, NG_VALIDATORS, FormControl } from '@angular/forms'
import { Directive,  Input } from '@angular/core';
import { gteService } from 'projects/injectService1/src/app/gte.service';
 
@Directive,({
  selector: '[gteValidator]',
  providers: [
    { provide: NG_VALIDATORS, useExisting: gteValidatorDirective, multi: true }
  ]
})
export class gteValidatorDirective implements Validator {
 
  @Input,("gteNum") gteNum:number
 
  constructor(private gteService:gteService) {
  }
 
  validate(c: FormControl) {
 
    let v: number = +c.value;
 
    if (this.gteService.gte(v,this.gteNum)) {
      return { 'gte': true, 'requiredValue': this.gteNum }
    }
 
    return null;
  }
}
 
                            
                        

Summary

We learned how to create a custom validator in template-driven forms. We also talked about how to pass parameter and inject service into our directive.