Home > Blockchain >  Custom Control Component Implementing ControlValueAccessor and Validator Not Staying In Sync With Co
Custom Control Component Implementing ControlValueAccessor and Validator Not Staying In Sync With Co

Time:01-12

Background:

I have a custom email control component (EmailControlComponent) that implements ControlValueAccessor and Validator. The validate() method of EmailControlComponent accepts a single AbstractControl parameter. Per Angular's API, the validate method is called each time the consuming parent FormGroup emits valueChanges on the customer email control.

Example:

Stackblitz

The Question:

Why is the validate() method's AbstractControl parameter out of sync with the parent FormGroup's status?

If you take a look at the demo above and view the console, you should see that the logged control.status is always VALID, regardless of the controls actual status. The parent FormGroup correctly shows the control's status toggling between VALID and INVALID appropriately, but the validate() parameter status never changes.

What am I doing wrong?

References:

https://angular.io/api/forms/ControlValueAccessor

https://angular.io/api/forms/NG_VALIDATORS

CodePudding user response:

Saw this on reddit and came here, so in short your custom email control doesn't need a formControl in it, you already have the formControl from the parent. You are extending the ControlValueAccessor, so you should/could have: @Optional() @Self() protected override controlDir: NgControl in your constructor and then assign it to itself controlDir.valueAccessor = this;

I'll try and find an example and update this post.

CodePudding user response:

When you have a custom form control that implements validator you can add a function validate. This function validate it's a function that return, based in the value of the control, null or an object.

But this custom form control can be feed with a FormControl that have Validators. (This is the aims to write in provider: multi: true,)

I want to say that your function validate should be, e.g.

validate(control: AbstractControl): ValidationErrors | null {
    const EMAIL_REGEXP =
    /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'* /=?^_`{|}~-] (?:\.[a-zA-Z0-9!#$%&'* /=?^_`{|}~-] )*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
    return EMAIL_REGEXP.test(control.value) ? null : {'email': true};
}

And when you create the FormControl only write

  email=new FormControl('',Validators.required)

Or not implement validator

Has no sense to have a validate function that only ask about control.valid

Update if we can "check" in the custom formControl if the formControl has external validators and it's fullfilled or not we can access to the function validator

Some like

validate(control: AbstractControl): ValidationErrors | null {
  const error=control && control.validator?
          control.validator(new FormControl(control.value)):
          null

  //in error we have the errors: the inner and the outer error

  ..rest of our code...
}

See that you can access to the "validator function" of the control. The only is feed with a new formControl with the same value than the control.value

So, the before code give us in error an object with the errors. Be careful, has the errors from outer and the inner error.

  • Related