Guide on creating a personalized validator for a form, incorporating validation rules that depend on information from an observable source

Currently, I am in the process of setting up a custom validator for a form. This validator will analyze the input from the form and cross-reference it with an array of values to ensure that the input is unique. The array used for this comparison is fetched from an Observable. Unfortunately, when attempting to access the array within the validation method, it appears as undefined. I suspect this issue arises because of the sequencing in relation to the subscribe function, but I have been unable to figure out the correct approach.

Below is a simplified version of the code that illustrates my objective. I've experimented with both of the validator functions provided. Additionally, I have attempted relocating the formgroup definition within the ngOnInit function and directly after populating allUserNames within the subscribe function.

export class userComponent implements OnInit {

  user: user = new user;
  allUserNames: string[];

  generalForm = new FormGroup({
    userName: new FormControl(
      this.user.name, [
        Validators.required,
        Validators.maxLength(20),
        this.UniqueNameValidator
        //,this.UniqueNameValidator1(this.alluserNames)
      ])
  })

  constructor(private userService: userService) { }

  ngOnInit() {
    this.subscribeUsers();
  }

  subscribeUsers(): void {
    this.getUsers().subscribe((users) => {
      this.allUserNames = Object.keys(users).map(itm => users[itm].name);
    })
  }

  getUsers(): Observable<user[]> {
    return this.userService.getUsers();
  }

  UniqueNameValidator(allUsers: String[]): ValidatorFn {
    return (control: AbstractControl): { [key: string]: boolean } | null => {
      allUsers.forEach((userName) => {
        if (userName === control.value) {
          return { 'notUnique': true };
        }
      });
      return null;
    }
  }

  UniqueNameValidator1(control: AbstractControl): { [key: string]: boolean } | null {
    this.allUserNames.forEach((userName) => {
      if (userName === control.value) {
        return { 'notUnique': true };
      }
    });
    return null;
  }
}

My expectation is that the validate function should compare the input string and flag it as not unique if a match is found in allUserNames. However, an error keeps popping up:

ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'forEach' of undefined  

I would greatly appreciate any guidance on resolving this issue!

Thank you.

Answer №1

There seems to be a scope problem with this. When you console log this, you'll notice it's not referring to the component, but rather your function.

An async validator would be ideal in this situation since you are making an HTTP call. It's recommended to utilize FormBuilder for form building purposes...

generalForm: FormGroup;

constructor(private userService: userService, private fb: FormBuilder) {
  this.generalForm = this.fb.group({
    userName: [this.user.name, 
              [Validators.required, Validators.maxLength(20)], 
              [this.UniqueNameValidator.bind(this)]]
  })
}

Async validators are set as the third argument. Notice the usage of bind(this) to ensure the correct scope.

The implementation of the validator could resemble the following:

import { of } from 'rxjs';
import { switchMap } from 'rxjs/operators'

UniqueNameValidator(ctrl: AbstractControl) {
  return this.userService.getUsers().pipe(
      switchMap((users: user[]) => {
        // perform necessary actions and return an error or "of(null)"
      })
  );

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

Is the transcluded content visible to the class as a whole?

Angular2 makes it simple to create a component like this: @Component({ selector: 'some', properties: ['header'] }) @View({ template: ` <div> <h2>{{ getFormattedHeader() }}</h2> <p><conte ...

Using Partial function input in TypeScript

I am in need of a function that can accept partial input. The function includes a variable called style, which should only have values of outline or fill, like so: export type TrafficSignalStyle = 'outline' | 'fill' let style: TrafficSi ...

Updating the Model in Angular 2: A Step-by-Step Guide

When receiving a data model through a service: return this.http.get(queryUrl, opts) .map((response: Response) => { return (<any>response.json()).data.map(el => { return new User({ id: item.id, name : item.name ...

"Enhance Your Form with Radio Buttons Offering an Alternative Selection

Currently, I am developing a reactive form in Angular. The initial inquiry on the form prompts users to indicate their favorite fruit. I am considering including an additional "other" option. <p> <label for="favFruit"><b>Wha ...

Unable to navigate to a page called "meeting" in NextJS 13 due to issues with router.push not functioning correctly

import { Input, Button } from '@nextui-org/react'; import router from 'next/router'; import { SetStateAction, useEffect, useState } from 'react'; const SignIn = () => { const [errorMessage, setErrorMessage] ...

Having trouble locating the Angular Material core theme within the asp.net core 2.0 template using Angular 5

CustomConfig.js const treeModules = [ '@angular/animations', '@angular/common', '@angular/compiler', '@angular/core', '@angular/forms', '@angular/http', '@angular ...

Failure to correctly apply CSS to Angular custom components causes styling issues

I have been working with a custom component and I have incorporated several instances of it within the parent markup. When I apply styles directly within the custom component, everything works as intended. However, when I try to set styles in the parent co ...

Highcharts encounters issues with dateRange values disappearing after a refresh in older versions of IE (9 and below) and Chrome

const newCurrentIndex = findIndexForCounter(currentPCData.CounterID, currentPCData.NetworkID); if (currentIndex === newCurrentIndex) { $.each(model.Data, (j, point) => { ...

The abundance of options in WebStorm's code completion for Node can be overwhelming

I recently finished a project using NodeJS and TypeScript. I made sure to install the type definition files with 'tsd install node'. The code begins with the following lines: var http = require('http'); var server = http.createServer(. ...

There was an issue with validating the initial certificate due to an error message stating "WWW-Authenticate: Bearer error="invalid_token", error_description="The signature is invalid

I have developed a spa application that generates tokens and now I need to validate these tokens in a web API. The application has been configured using the methods outlined in Azure's official documentation. Here is the link to the configuration app ...

Developing a cutting-edge project: Integrating Angular with PrimeNG to create a dynamic Sakai skeleton demo

I have just cloned the Sakai angular skeleton repository from this location: git clone https://github.com/primefaces/sakai-ng.git In the default setup, the 'landing' URL is set to the Sakai demo. However, I would like my base URL to point to my ...

Tips for incorporating the closeAutocomplete function into ng4-geoautocomplete

Hey there! I've incorporated the ng4-autocomplete component into my custom component and now I'm trying to figure out how to detect when the autocomplete dropdown closes. Can you help me out with implementing the "closeAutocomplete" method? Let& ...

Configuring Stylelint in a NextJS project using Emotionjs

I recently encountered an issue while trying to integrate Stylelint into a new NextJS Typescript project with EmotionJS. Many rules were not working in my styles files, and the only error I could identify was Unknown word CssSyntaxError. This particular U ...

Can you explain how TypeScript module resolution handles global values?

After installing @types/jest, I noticed that jest's corresponding typescript definitions were detected automatically. However, when I started implementing integration tests with cypress (which uses mocha), I encountered a problem where mocha type defi ...

fp-ts/typescript steer clear of chaining multiple pipes

Is there a more concise way to handle nested pipes in fp-ts when working with TypeScript? Perhaps using some form of syntactic sugar like Do notation? I'm trying to avoid this kind of nested pipe structure: pipe( userId, O.fold( () => set ...

Adding properties to request object on-the-fly - Google Pay [Typescript]

Here is how I am constructing the payment request object: paymentRequestObject: google.payments.api.PaymentDataRequest = { apiVersion: 2, apiVersionMinor: 0, allowedPaymentMethods: [ { type: 'CARD', parameters: { allowedAuthMethod ...

Setting or passing a variable via URL in Angular 2 applications

I am working on an Angular2 application that includes a chart component. Users can adjust the chart by setting certain variables. I want to give users the option to have the chart preset with specific variables by using a URL link. For instance: localhost ...

Utilizing a wysiwyg text editor in conjunction with Angular 2

I am currently implementing a wysiwyg feature in my Angular2 project. When I include the code in the index.html page (the root page), it functions correctly. However, when I try to use it in a child view HTML file, the CSS and JavaScript do not load prope ...

Tips for integrating JavaScript libraries into TypeScript build process in Visual Studio

Is it possible to configure the "TypeScript Build" feature in Visual Studio 2017 to include both Javascript libraries and TypeScript files in the generated bundle.js output? ...

Encountering a 401 Error while integrating Azure App Configuration within an Angular 9 Application

After implementing the library found at https://www.npmjs.com/package/@azure/app-configuration Despite following the setup instructions, I encounter a 401 error whenever I make a request using the AppConfigurationClient. The response headers indicate: ww ...