Reputation: 36311
I have a cross field validation method that should fail if one of the following evaluates to true:
country == 'United States'
and stateSelect
is emptycountry != 'United States'
and stateText
is emptycountry
and stateSelect
are both <select>
items while sateText
is an <input type="text">
. When I load the page country = 'United States'
and stateSelect = {name: 'Alabama', abbr: 'AL'}
, and everything evalues properly.
If I change country to another value in the select, then change it back to United States
, it evaluates properly, but my button stays disabled.
<form [formGroup]="purchase" class="forum-purchase__grid">
<!-- inputs and selects -->
<button [disabled]="purchase.invalid">Next</button>
</form>
The component looks like this:
public constructor() {
this.purchase = new FormGroup({
stateSelect: new FormControl(this.selectedState),
stateText: new FormControl(''),
country: new FormControl(this.selectedCountry, [Validators.required]),
}, { validators: [this.stateRegionValidator] });
}
private stateRegionValidator(formGroup: FormGroup): ValidationErrors | null {
const stateSelect = formGroup.get('stateSelect');
const stateText = formGroup.get('stateText');
const country = formGroup.get('country');
// Validate the fields
if (country.value === 'United States' && !stateSelect.value) {
stateSelect.setErrors({ 'badState': true });
return { 'badState': true };
} else if (country.value !== 'United States' && !stateText.value.trim().length) {
stateText.setErrors({ 'badRegion': true });
return { 'badRegion': true };
}
// The validation was successful.
return null;
}
I do notice that this works if I remove these two lines, however, I don't get error styles on the inputs then:
stateSelect.setErrors({ 'badState': true });
stateText.setErrors({ 'badRegion': true });
Upvotes: 0
Views: 1422
Reputation: 3276
In some cases, I was needed to do something like this. listen on value change:
<select [(ngModel)]="selectedCountry" (ngModelChange)="test($event)" formControlName="country">
and in TS:
countryUpdate($event: string) {
if ($event == 'United States') {
this.purchase.controls.stateText.clearValidators();
} else {
this.purchase.controls.stateText.setValidators([this.stateRegionValidator]);
}
this.purchase.updateValueAndValidity();
}
Upvotes: 0
Reputation: 6257
So your button is still disabled, because you did not remove the previously set errors from your different form controls.
When you add following above your return null;
it will work:
stateSelect.setErros(null);
stateText.setErrors(null);
Upvotes: 1
Reputation: 25525
The issue is what you called out - you need to remove the setErrors
calls. Those are side effects of your group validator which validates the form as a whole. When those set errors on the individual fields, nothing can unset them.
You should probably write custom validators for each field that use the logic in your group validator function, while not calling setErrors and just returning null or a value. Or keep the group validator, and show a single error for when the group has an error.
Upvotes: 1