Search code examples
angularformsvalidation

How can I reach component variables in custom validator?


I want to make custom validator which would make submit button available only if text in form is unique. I have VulnarabilitiesClass instance, which contains an array of objects with id and name fields. After typing any text in my form I get this error: Error: undefined is not an object (evaluating 'this.systemVulnarabilities')

<form [formGroup]="profileForm">
  <label>
    Vulnarability Name:
    <input type="text" formControlName="name" required>
  </label>
</form>

<p>
  Form Status: {{ profileForm.status }}
</p>
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
this.systemVulnarabilities = new VulnarabilitiesClass();

profileForm = this.fb.group({
    name: ['', Validators.required,this.UniqueNameValidator],
  });

private UniqueNameValidator(control: FormControl): ValidationErrors{
  let vulnarabilityName: string = control.value;
  console.log(vulnarabilityName);
  console.log(this.systemVulnarabilities.displayList.toString());//no output already
  let found: number = this.systemVulnarabilities.displayList.map(function(e) { return e.name; }).indexOf(vulnarabilityName); //mistake
  if(found === -1){
    return {invalidPassword: 'this name already exists'};
  }
  return null;
}

Solution

  • This error happens because UniqueNameValidator method is executed with different from component context this. The reason for this is that in javascript context this depends on how the function is executed and not where it was declared.

    The simple fix is to use Function.prototype.bind method that makes sure correct context this

    this.UniqueNameValidator.bind(this)
    

    Also, if your validator is synchronous then you need to wrap your validators in array otherwise Angular will treat it as asynchronous validator:

    name: ['', [Validators.required, this.UniqueNameValidator.bind(this)]],