Search code examples
angulartypescriptangular-reactive-formsangular-formsangular-validation

Angular reactive forms and custom validator error


In my Angular 4 app, I have a custom form validator that looks like this:

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

export function myCustomValidator(myCustomArg: string): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {

    if (control.value) {
      // do some checks with control.value and myCustomArg
      // return error if needed
    }

    // return null otherwise
    control.setErrors(null);
    return null;
  };
}

but when I try to use it in one of my reactive forms:

  ngOnInit() {
    this.form = new FormGroup({
      'myControl': new FormControl(null, [ myCustomValidator(...) ]),
      // ...
    });
  }

I get several errors:

ERROR TypeError: Cannot read property 'emit' of undefined at FormControl.webpackJsonp.../../../forms/@angular/forms.es5.js.AbstractControl._updateControlsErrors (forms.es5.js:2836) at FormControl.webpackJsonp.../../../forms/@angular/forms.es5.js.AbstractControl.setErrors (forms.es5.js:2772) at file-extension.validator.ts:17 at forms.es5.js:506 at Array.map () at _executeValidators (forms.es5.js:506) at FormControl.validator (forms.es5.js:462) at FormControl.webpackJsonp.../../../forms/@angular/forms.es5.js.AbstractControl._runValidator (forms.es5.js:2720) at FormControl.webpackJsonp.../../../forms/@angular/forms.es5.js.AbstractControl.updateValueAndValidity (forms.es5.js:2688) at new FormControl (forms.es5.js:3011)


ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 0, nodeDef: {…}, elDef: {…}, elView: {…}}


ERROR Error: formGroup expects a FormGroup instance. Please pass one in.

But unfortunately they are not very helpful.


Solution

  • The issue is related with the way the validator is assigned to the field.

    In fact, the validator is trying to access to the control's value control.value.

    But when the validator factory function is called, the control doesn't exist yet:

    this.form = new FormGroup({
      'myControl': new FormControl(null, [ myCustomValidator(...) ]),
      // ...
    });
    

    So in order to solve the issue, just create the form first and then assign the validator:

    ngOnInit() {
       // first create the form with its controls
      this.form = new FormGroup({
        'myControl': new FormControl(null),
        // ...
      });
    
      // then assign the custom validator
      this.form.get('myControl').setValidators([
        myCustomValidator(...),
      ]);
    }