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:
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.