Get validators present in FormGroup/FormControl
This answer is a continuation of @joh04667's. They wrote:
public hasValidator(control: string, validator: string): boolean {
return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
// returns true if control has the validator
}
However there is no AbstractControls.validators()
method. I'm assuming AbstractControls.validator()
was meant.
The hasValidator()
method only works for validators that 'fail' (eg. a required validator on a control with the value '' (empty)). Since if they pass they return null. A way around this would be to set the value so that it always fails and restore that afterwards.
public hasValidator(control: string, validator: string): boolean {
let control: AbstractControl = this.myForm.controls[control];
let lastValue: any = control.value;
switch(validator) {
case 'required':
control.setValue(''); // as is appropriate for the control
case 'pattern':
control.setValue('3'); // given you have knowledge of what the pattern is - say its '\d\d\d'
....
}
let hasValidator: boolean = !!control.validator(control).hasOwnProperty(validator);
control.setValue(lastValue);
return hasValidator;
}
And this is pretty horrible. It begs the question - Why is there no AbstractControl.getValidators(): ValidatorFn[]|null
?
What is the motivation in hiding this? Perhaps they are worried someone might put in their code:
...
secretPassword: ['', [Validators.pattern('fjdfjafj734738&UERUEIOJDFDJj')]
...
Angular doesn't really provide a great, clean way to do this, but it is possible. I think the validators are stored in a service that is injected into the FormBuilder(NG_VALIDATORS
), and I'm going to look into hijacking that service or injecting it into a component, but for now this will work:
The docs and the source show a validator
member on AbstractControl
typed to ValidatorFn
. ValidatorFn
unfortunately simply has a null
typing, so we can't see what's going on. However, after poking through the generated source and probing an app, it seems we can pass this validators
method a control
parameter, which will return an object of all validators present on that control, regardless of whether or not it's passing.
Strangely, this only works on the FormControl
itself and not the FormGroup
(on the FormGroup
, the validators
member is not a function and was always null
in my testing). The compiled JS says this function takes a control
parameter; I've tried passing in FormControl
references but as far as I can tell it will just return the validators on the control as long as this parameter is not null.
Getting validators on a FormControl
// in the constructor
this.myForm = this.formBuilder.group({
'anyCtrl': ['', Validators.required],
'anotherCtrl': ['', Validators.compose([Validators.required, Validators.email])]
});
// later on
let theValidators = this.myForm.controls['anyCtrl'].validator('');
console.log(theValidators) // -> {required: true};
let otherValidators = this.myForm.controls['anotherCtrl'].validator('');
console.log(otherValidators); // -> {required: true, email: true}
Making it easier to grab:
public hasValidator(control: string, validator: string): boolean {
return !!this.myForm.controls[control].validator(control).hasOwnProperty(validator);
// returns true if control has the validator
}
and in your markup:
<md-input-container>
<input placeholder="Placeholder"
mdInput [formControl]="anyCtrl"
[required]="hasValidator('anyCtrl', 'email')">
</md-input-container>
Special case for Validators.required
The required
validator has a shortcut. The [required]
binding is actually an instance of the RequiredValidator
directive (line 5022 of source/forms.js). This directive actually will add the required
Validator to the FormControl
it's on. It's equivalent to adding Validators.required
to the FormGroup
upon initialization. So, setting the bound property to false will remove the required
Validator from that control and vice versa...either way, the directive affects the FormControl.required
value, so binding it to a property that it changes won't really do much.
The only difference is that the [required]
directive adds the asterisk to the placeholder while Validators.required
does not.
I'm going to keep looking into NG_VALIDATORS
, but I hope this helps for now!
Angular v12.2 introduced hasValidator()
: https://github.com/angular/angular/pull/42838
Example: this.formGroup.controls['anyCtrl'].hasValidator(Validators.required)
You can also add or remove validators later programatically. See addValidators()
, removeValidators()
, and others.
https://angular.io/api/forms/AbstractControl#hasValidator