Angular 2 Validation Customizer

Recently, I created a web API function that takes a username input from a text field and checks if it is already taken. The server response returns Y if the username is available and N if it's not.

For validating the username, I implemented a ValidatorFn in Angular2, however, I encountered an issue with my validator function.

Below is the code for the validator function:

interface Validator<T extends FormControl> {
  (c: T): { [error: string]: any };
}

function validateUsername(c: string) : ValidatorFn {
  return (this.isAvailable(c)=='Y') ? null : {
    validateUsername: {
      valid: false
    }
  };
}

Next, here is the implementation of the isAvailable function:

private isAvailable(username: string) {
  let usernameAvailable;
  let url = 'URL/api/auth/checkuser/' + username;
  let headers = new Headers();
  headers.append('User', sessionStorage.getItem('username'));
  headers.append('Token', sessionStorage.getItem('token'));
  headers.append('AccessTime', sessionStorage.getItem('AccessTime'));

  let options = new RequestOptions({ headers: headers });

  this.http.get(url, options)
    .subscribe((res: Response) => usernameAvailable);
  return usernameAvailable; //returns Y or N
}

Here is the part related to Form Builder:

complexForm: FormGroup;
constructor(private http: Http, fb: FormBuilder) {

  this.complexForm = fb.group({
    'username': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10), validateUsername(this.complexForm.controls['username'].value)])],
  })
}

The snippet

validateUsername(this.complexForm.controls['username'].value)
appears to be failing and resulting in the following error message:

[ts] Type '{ validateUsername: { valid: boolean; }; }' is not assignable to type 'ValidatorFn'.   Object literal may only specify known properties, and 'validateUsername' does not exist in type 'ValidatorFn'. (property) validateUsername: {
    valid: boolean;
}

Answer №1

Your validator function is not being added correctly. It's unnecessary to call the function when registering it:

this.complexForm = fb.group({
  'username': [null, Validators.compose(
    [
      Validators.required,
      Validators.minLength(5),
      Validators.maxLength(10),
      validateUsername    <----- avoid calling it here
    ]
  )],
})

You can observe that some functions are invoked:

Validators.minLength(5),

However, this is a factory function call rather than a validator function call. When initialized, they return ValidatorFn:

/**
   * Validator that requires controls to have a value of a minimum length.
   */
  static minLength(minLength: number): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
       ...
  }

For more details, refer to the official documentation.

Additionally, if your validator is asynchronous, you need to place it in the async array. It appears that you don't require Validators.compose. The correct setup should be as follows:

this.complexForm = fb.group({
  'username': [null, [
    Validators.required,
    Validators.minLength(5),
    Validators.maxLength(10),
  ], [validateUsername]]
})

Regarding the error message:

Type '{ valid: boolean; }' is not assignable to type ValidatorFn.

Ensure you use the proper return type ValidationErrors instead of ValidatorFn:

function validateUsername(c: string) : ValidationErrors {
  return (this.isAvailable(c)=='Y') ? null : {
    validateUsername: {
      valid: false
    }
  };
}

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

How can I transfer the document id from Angular Firestore to a different component?

I'm seeking assistance on how to achieve a specific task related to pulling data from Firestore in my Angular application and displaying it in a list. Everything is working smoothly, including retrieving the document ID. My goal is to have the retrie ...

Establish a connection between two JSON files using the WordPress REST API

I have developed an app using ionic 2 that revolves around quotes. My goal is to manage these quotes (along with authors, categories, etc) using Wordpress and its REST API. Initially, I utilized normal posts for this purpose, but now I am exploring custom ...

Angular2 Service Failing to Return Expected Value

It's frustrating that my services are not functioning properly. Despite spending the last two days scouring Stack Overflow for solutions, I haven't been able to find a solution that matches my specific issue. Here is a snippet of my Service.ts c ...

Ignore TypeScript errors when using TSNode with Mocha by forcing the compiler to emit code despite errors and having TSNode execute the emitted code

Below is a code snippet where the function test2 is invalid, but it should not affect testing of function test1: export function test1(): boolean { return true; } export function test2(): number { return "1"; } Test: import { assert as Assert } fr ...

defining data types based on specific conditions within an object {typescript}

Can someone help with implementing conditional function typing in an object? let obj = { function myfunc (input: string): number; function myfunc (input: number): string; myfunc: function (input: string|number):string|number { ... } } I've been ...

ajax-triggered forms

Is there a way to ensure that a form functions correctly when it is included in the HTML loaded via AJAX? I am utilizing jQuery for this task. Any suggestions or advice would be appreciated. ...

Using TypeScript to convert a JSON date string into a Date object

The backend is sending me a JSON data structure that resembles the following: [{ "schedulingId": "7d98a02b-e14f-43e4-a8c9-6763ba6a5e76", "schedulingDateTime": "2019-12-28T14:00:00", "registrationDateTime": "2019-12-24T16:47:34", "doctorVie ...

Aligning validation schema with file type for synchronization

Below is the code snippet in question: type FormValues = { files: File[]; notify: string[]; }; const validationSchema = yup.object({ files: yup .array<File[]>() .of( yup .mixed<File>() .required() .t ...

Enabling or disabling cell editing dynamically in Ag-grid based on another field's value

I'm currently working with ag-grid in Angular and implementing full row editing. One requirement I have is to dynamically disable editing for a specific field based on the value of another field. However, I need this field to be disabled or enabled im ...

Crafting a recursive Typescript Immutable.js Record through typing

I am currently working on representing a tree-like data structure using immutable js and typescript. At the moment, I am utilizing regular vanilla js objects to depict the nodes within the tree. Below is the type signature. type NodeType = { value: str ...

Encountering issues with material 2 autoComplete onSelect() function after transitioning to Angular4

I recently made the transition to Angular 4 and material 2, but I'm encountering an issue with the autoComplete's onSelect() on md-option. It seems to be not working anymore and I can't seem to find any relevant documentation. Has anyone els ...

Experiencing the 'invalid_form_data' error while attempting to upload a file to the Slack API via the files.upload method in Angular 8

I am currently working on a project that involves collecting form data, including a file upload. I am trying to implement a feature where the uploaded file is automatically sent to a Slack channel upon submission of the form. Despite following the guidance ...

Is there an automatic bottom padding feature?

Currently, I am facing a challenge in fitting the loader into the container without it being overridden by the browser. Using padding-bottom is not an ideal solution as it results in the loader appearing un-resized and unprofessional. Any suggestions or co ...

Implementing dynamic progress bar updates in an Angular application using Bootstrap

Seeking to create a progress bar in a Word object for a language vocabulary training app, displaying the number of correct and wrong answers. <div class="progress"> <div class="progress-bar progress-bar-striped progress-bar-a ...

Issues with submitting the Ajax form

I'm currently working on implementing a "Save Changes" button for a form that will utilize ajax to send data to the update method in the controller. This feature is designed to enable users to save their progress without having to reload or redirect t ...

Validator for IP addresses in Angular reactive forms

Hey there, I'm currently trying to implement a validator for an IP address in Angular. Strangely, even when I input an invalid IP address like 12.2.2.2..., the GUI indicates it is valid (as shown in the image). However, the console logs reveal that it ...

Position Bootstrap Modal in the center horizontally

I am working on an Angular project and struggling to center my Bootstrap 3 Modal horizontally on the screen. Despite trying various solutions like using text-align: center and align = "center", I have been unsuccessful. Can someone guide me on how to prope ...

Angular - Enhance ngFor index while filtering

I am currently working with a list that utilizes an *ngFor loop in the template: <li *ngFor="let product of products | filterProducts: selectedFilter; index as productId"> <a [routerLink]="['/product', productId]"> {{produc ...

Utilizing the component as both a custom element and an Angular component

I have been experimenting with using an Angular component as a custom element, allowing me to dynamically add it to the DOM and have it automatically bootstraped. However, I also need this component to be included in another component's template. Cur ...

Choosing an option from a dropdown menu in Google Forms using Puppeteer in NodeJS

Hey everyone, I've been working on automating a Google form and I'm facing an issue with a dropdown menu. I'm struggling to select the desired value from the dropdown list. When I use Puppeteer to type in "United space Kingdom," it autocomp ...