What is the process for implementing a custom validator in Angular?

After creating a custom validator, I implemented it in my Angular project like this:

import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms";

export function notInSet(theSet: Set<string>): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
        const val = control.value;
        if(theSet.has(val))
            return {InSet: true};
        else
            return null;
    }
}

Next, in the template file, I added the usage of the custom validator to validate user input:

    <form #myForm novalidate>
        <input pInputText [(ngModel)]="name" name="name" notInSet="existingNames" #theName="ngModel"/>
        <div *ngIf="!theName.valid" class="text-error">
            Please provide a unique name for this API
        </div>
    </form>

In this code snippet, the variables existingNames and name are defined in the corresponding TypeScript file.

However, despite implementing the custom validator, it seems that the validation function is never triggered. I suspect that I need to register it in a specific location within the Angular application, but I'm uncertain about where exactly that should be.

Answer №1

To successfully implement a custom validator for template driven forms, it is necessary to create a directive. Below is a functional example available on stackblitz that you can refer to and integrate into your project. Feel free to reach out if you have any questions or uncertainties!

directive

import { Directive, Input } from '@angular/core';
import {
  NG_VALIDATORS,
  Validator,
  AbstractControl,
  ValidationErrors,
} from '@angular/forms';

@Directive({
  selector: '[notInSet]',
  providers: [
    {
      provide: NG_VALIDATORS,
      useExisting: NotInSetDirective,
      multi: true,
    },
  ],
  standalone: true,
})
export class NotInSetDirective implements Validator {
  @Input() notInSet!: Map<string, number>;
  constructor() {}

  validate(control: AbstractControl): { [key: string]: any } | null {
    const val = control.value;
    if (this.notInSet.has(val)) return { InSet: true };
    else return null;
  }
}

main.ts

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import 'zone.js';
import { CommonModule } from '@angular/common';
import { NotInSetDirective } from './validator.directive';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule, FormsModule, NotInSetDirective],
  template: `
    <form #myForm novalidate>
        <input pInputText [(ngModel)]="name" name="name" [notInSet]="existingNames" #theName="ngModel"/>
        <div *ngIf="!theName.valid" class="text-error">
            Please provide a unique name for this api
        </div>
        {{theName.valid | json}}
    </form>
  `,
})
export class App {
  name = 'Angular';
  existingNames = new Map([
    ['apples', 1],
    ['bananas', 1],
    ['oranges', 1],
  ]);
}

bootstrapApplication(App);

View code snippet on Stackblitz

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Executing an ajax request following validation

I am facing an issue with my ajax insert script and validation script. Currently, the insert script is executing regardless of the validation result. How can I modify my code to ensure that the insert query only runs after successful validation? Below is ...

Workers in Async.js queue failing to complete tasks

Creating a job queue to execute copy operations using robocopy is achieved with the following code snippet: interface copyProcessReturn { jobId: number, code: number, description: string, params: string[], source: string, target: s ...

Challenges with creating custom directives in Angular2

Recently, I was working on a project where I came across a tutorial online that caught my attention. You can check it out here. Following the tutorial closely, I ended up creating a unique directive: import {Component, View} from 'angular2/core&apos ...

Transferring data between unrelated Angular2 components

I have two components that are quite far apart in the component hierarchy - one could be considered a 3rd removed grandparent of the other. I am trying to find a way to pass data between these components. Initially, I attempted to achieve this by creating ...

The property 'props' is not found in the TypeScript code

I am encountering an issue with my .tsx file: import React, { Component } from 'react'; export class SidebarItem extends Component { constructor(props) { super(props); } render() { return (<li>{this.props.children}</li& ...

Unable to locate module within an Angular 2 TypeScript class

I am experiencing an issue with my TypeScript file, here is a snippet of the code: import { Component, OnInit } from '@angular/core'; import { BookService } from "../../services/book.service"; import { Book } from "../../Models/book"; @Compone ...

Error: The "require" function is undefined and cannot be recognized in app.js on line 3

Encountering difficulties in connecting front-end HTML to a private blockchain for interacting with a smart contract. Steps completed thus far: Created a smart contract and deployed it on the private blockchain. npm install -g web3 Developed an HTML fil ...

Tips for resetting an element to its original state after using jquery slideUp

Check out this snippet of HTML: <div *ngIf="msgVisible == true" class="success_trip_msg" role="alert"> <div>trip successfully saved</div> </div> Once the data is saved, I utilize some jQuery to s ...

Arranging Typescript strings in sequential date format

Looking for guidance on how to sort string dates in chronological order, any expert tips? Let's say we have an array object like: data = [ {id: "1", date: "18.08.2018"} {id: "2", date: "05.01.2014"} {id: "3", date: "01.01.2014"} {id: ...

The health check URL is experiencing issues: Unable to locate any routes

I am currently developing a .net Core 2.2/Angular 8 application and recently came across the HealthCheck feature. I decided to incorporate it into my application, so here is a snippet from my Startup.cs file: using HealthChecks.UI.Client; using Mi ...

What is the best way to encrypt the JWT decode token payload using Angular 8 on the client-side?

Currently, I am utilizing angular2-jwt to handle the code following an http.get request. In order to properly send an http post request, I must encode the body. let body = { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }; this.http.pos ...

Is it possible to utilize HTTP/2 server push to deliver assets from a different CDN?

My angular app's index.html file is currently being generated from a Tomcat server (Apache Coyote). This file contains js, css, and images that point to our own CDN. For example: <script src="https://mc1.mcdn.in/main.adjhf432hjh23k44.js" /> If ...

The process of arranging the order in which files are packaged during the build in Angular

I am currently working on an Angular project that requires support for localization. To achieve this, we are loading translations from json files before the module is loaded. In my main.ts file, I have added this code snippet: loadTranslationsFromJson(extr ...

How do I go about creating shades when working with material theming?

Hello everyone! I am interested in developing a unique theme with Angular Material theming, incorporating my own set of three colors. Typically, the Angular Material themes are defined with shades like this: $mat-red: ( 50: #ffebee, 100: #ffcdd2, 20 ...

Oops! It seems like we're encountering an issue here. The reference error states that

I am trying to integrate the Google Maps API into my Angular web application, but I keep encountering the following error: ERROR ReferenceError: google is not defined Even though I have followed the instructions in the official Google documentation, it st ...

Not all generic types specified with an extends clause are appropriately narrowed down as expected

Consider the following scenario: type MyType = 'val1' | 'val2' | 'val3'; const variable = 'val1' as MyType; const val2 = 'val2'; const val3 = 'val3'; declare function test<U extends MyType&g ...

Having trouble getting Angular Module Federation to work with multiple repositories

I've successfully built a monorepo project with multiple micro frontends, but I'm facing challenges when trying to integrate a micro frontend from a different repository. Shell: webpack.config.js new ModuleFederationPlugin({ library: { t ...

NGXS: Issue with passing objects to "setState" occurs when any of the patched inner fields is nullable or undefined

In my Angular components, I have created a class that is responsible for storing the state: export class MyStateModel { subState1: SubStateModel1; substate2: SubStateModel2; } This class has simple subclasses: export class SubStateModel1 { someField ...

The error occurred due to an invalid regular expression when trying to create a route with route parameters

In my development process, I have a specialized class for creating routes and another class for bundling these routes before adding them to an express app or router. However, I encountered a problem with my route class when I attempted to create a route wi ...

I am interested in utilizing the request-reply pattern with KafkaJS in a TypeScript environment. Could you provide guidance on how to successfully implement this?

I am new to Kafka and I am trying to implement the request-reply pattern using kafkajs in TypeScript. However, my current implementation is very basic and the consumers inside producers are taking too long to start, causing delays. Is there a better way to ...