Custom form validation in Angular 2+ causes dysfunction in the form functionalities

I am facing an issue with my form setup:

public initializeUserForm(user: User = null): void {
    this.selectedUserForm = this.fb.group({
      id: 0,
      isActive: [true],
      isSuperUser: [null],
      firstName: ['', Validators.required],
      lastName: ['', Validators.required],
      username: ['', [Validators.required, UniqueNameValidator(this.userNamesList, user)]],
      password: ['',
        Validators.pattern('^(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])(?=\\D*\\d)[A-Za-z\\d!$%@#£€*?&]{8,}$')],
      emailAddress: ['', Validators.email],
      businessEmailAddress: ['', Validators.email],
      address1: ['', Validators.maxLength(50)],
      address2: ['', Validators.maxLength(50)],
      city: ['', Validators.maxLength(30)],
      stateProvince: ['', Validators.maxLength(30)],
      postalCode: ['', Validators.maxLength(10)],
      phoneNumber1: ['', Validators.maxLength(10)],
      employeeId: [''],
      notes: ['']
    });
    this.onFormChanges();
  }

In addition to the form setup, I have a custom validator implemented as well:

import { Directive } from '@angular/core';
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';

Directive({
  selector: '[uniqueName]'
});

export function UniqueNameValidator(array: any[], exception = null): ValidatorFn {
  const valObject = { nameDuplicate: true }
  return (control: AbstractControl): ValidationErrors | null => {
    if (exception) {
      if (control.value === exception.name || control.value === exception.username) {
        return array.findIndex(item => item.name === control.value || item.username === control.value) > 0 ? valObject : null;
      } else {
        return array.findIndex(item => item.name === control.value || item.username === control.value) > 0 ? valObject : null;
      }
    } else {
      return array.findIndex(item => item.name === control.value || item.username === control.value) > 0 ? valObject : null;
    }
  };
}

Although the custom validation works correctly, it seems to interfere with the form's built-in functionality. The methods like this.selectedUserForm.touched or this.selectedUserForm.valid do not provide accurate results and always return False. What steps can I take to fix this issue without compromising the custom form validation?

Answer №1

Ensure that your validator function returns an error if the value is not unique.

uniqueValidation(list: string[]): ValidatorFn {
    return (c: AbstractControl): { [key: string]: boolean } | null => {  
      if (c.value === null || c.pristine || c.value === '') {
        return null;
      } else if (c.dirty) {
        return (list.find(x => x === c.value)) ? { 'notunique': true } : null;
      }
      return null;
    }
  }

How to use this validator:

selectedUserForm: FormGroup;
  userNamesList: string[] = ['name1', 'name2']

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.buildForm();
  }

  uniqueValidation(list: string[]): ValidatorFn {
    return (c: AbstractControl): { [key: string]: boolean } | null => {  
      if (c.value === null || c.pristine || c.value === '') {
        return null;
      } else if (c.dirty) {
        return (list.find(x => x === c.value)) ? { 'notunique': true } : null;
      }
      return null;
    }
  }

  buildForm() {
    this.selectedUserForm = this.fb.group({
      userName: [null, [Validators.required, this.uniqueValidation(this.userNamesList)]]
    });
  }

Check out the live demo here: https://stackblitz.com/edit/angular-unique-validator-akeje2?file=src%2Fapp%2Fapp.component.ts

In the demonstration, try typing 'name1' or 'name2' to see the validation fail and receive a message indicating that the input is not unique.

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

Encountering [Object Object] within an angular2 app

https://i.stack.imgur.com/iceKH.pngI recently created an angular2 application using ngrx/effects for handling http calls. My reference point was an application on GitHub. However, I am facing an issue where the response from the HTTP call is not displaying ...

Developing a zod blueprint for a versatile interface

Recently, I created a basic interface to handle paginated responses. It looks like this: export interface PaginatedResponse<T> { pageIndex: number; pageSize: number; totalCount: number; totalPages: number; items: Array<T>; } Now, I w ...

Update angular2 to the latest 2.4.1 release, moving up from version 2.1.1

My goal is to upgrade my Angular2 version from 2.1.1 to 2.4.1 I started with this seed project. This was my original package.json content: { "name": "angular2-webpack-starter", "version": "5.1.1", "description": "An Angular 2 Webpack Starter ki ...

Can browser-sync be used to update sass/css for angular 2 components through injection?

Currently, I am using browser-sync to dynamically inject and modify the CSS in my application's root stylesheets that are not directly managed by Angular. Surprisingly, this process does not require a reload. However, I have noticed that any changes ...

Creating a dynamic web application with Laravel 5.5 and an interactive mobile app with Ionic 3

Currently, I have a web application developed on Laravel 5.5 with a MySQL database and am interested in creating a mobile app utilizing Ionic 3/Angular 5. My understanding is that Ionic requires Firebase as its backend for functionalities like sockets (wh ...

Error in Cross-Origin Resource Sharing (CORS) with Angular 2 and Slim

I am currently in the process of connecting Angular 2 frontend with Slim 3 PHP backend. Here is the Angular 2 service I have: import { Injectable } from '@angular/core'; import { Http, Headers, RequestOptions, Response } from '@angular/ ...

Ways to dynamically display components in React Native

In my React Native app, I have a custom tab control that is rendered dynamically using the following configuration: const TABS = [ { title: 'Tab 1', component: MyComponentOne }, { title: 'Tab 2', component: MyComponentTwo } ]; T ...

PrismaClientInitializationError: The connector encountered an issue when attempting to establish a database connection in VScode

For the past 48 hours, I've been facing this persistent issue. I've exhausted all possible solutions - tried resetting cache, flushing DNS, and every other method to reset ports. I even went as far as reinstalling VScode, but to no avail 1 Inter ...

Steps to add annotations to a class descriptor:

Can you help me with the correct way to annotate this piece of code? export class TestCls { static SomeStaticFn(): TestCls { // Do some stuff... // Return the class descriptor for a "fluid usage" of SomeStaticFn return TestCls ...

Latest Angular 2 Release: Lack of visual updates following asynchronous data entry

Currently, I am working with Angular2-Beta1, However, the templating from the "*ngFor" is not working properly and is only displayed as <!--template bindings={}--> and not as <template ...></template> as described here on the Angular2 G ...

Tips for utilizing a ternary operator to set a className in an element

I'm in the process of developing a website using React and Next.js. One of the components on my site is section.tsx, which displays a subsection of an article based on the provided props. I'm looking to add an 'align' property to this c ...

MobX React not causing re-render when props change

Just diving into MobX and encountering some roadblocks while trying to call async actions. In my store, there's an async function responsible for updating an observable array: export class AccountStore implements IAccountStore { @observable accounts ...

.bail() function does not function properly when used in conjunction with express-validator

While registering a new user, I require their name, email, and password. If no name is provided, there is no need for the backend to validate the email. I believe that the use of .bail() in express-validator should handle this situation, but unfortunately ...

Encountering an error message about 'resolving symbol values statically' while building an Angular 2 project

Currently, I am utilizing an older module called angular-2-local-storage. The initialization process is as follows: const LOCAL_STORAGE_SERVICE_CONFIG_TOKEN: string = 'LOCAL_STORAGE_SERVICE_CONFIG'; export const LOCAL_STORAGE_SERVICE_CONFIG = ne ...

Utilizing UseRef in Typescript for an Idle Timer

Feeling frustrated with Typescript, everything seems unnecessarily complicated. Trying to follow a tutorial on react-idle-timer and encountering TypeScript compilation issues within minutes. The guides online suggest using when calling useRef with TypeS ...

Looking to migrate my current firebase/react project to typescript. Any tips on how to batch.update?

Having difficulty resolving a typescript error related to batch.update in my code. const batch = db.batch(); const listingDoc = await db.collection("listings").doc(listingID).get(); const listingData = listingDoc.data( ...

tips for instructing the p-table to sort particular columns by utilizing a subfield

I currently have data structured with nested JSON as follows: users = [ { name: "ABC", age: 11, activity : { date: 11-Aug-2020, title: "some activity", loc: "so ...

Encountering the error message 'array expected for services config' within my GitLab CI/CD pipeline

My goal is to set up a pipeline in GitLab for running WebdriverIO TypeScript and Cucumber framework tests. I am encountering an issue when trying to execute wdio.conf.ts in the pipeline, resulting in this error: GitLab pipeline error Below is a snippet of ...

A step-by-step guide on reversing options in the Ant Design Cascader component

By default, the Cascader component's options are nested from left to right. I am looking to have them go from right to left instead. However, I could not find anything in the component's API that allows for this customization. Is it even possibl ...

Filtering JSON Data in Angular 2 Using Form Selection

I need help extracting specific JSON values based on user-selected input keys and converting them into QuestionBase<any>[]. Currently, my code successfully extracts values for the key "test" only: // dropdown HTML <select class="form-control" na ...