Validation in Angular 2 is pretty straight forward which is awesome. However, how would one go about making a required field optional if some other field is selected.
Here are my rules
this.contractsFilter = this.fb.group({
selectedContractType: ['', [Validators.required]],
selectedYear: ['', [Validators.required]],
selectedPde: ['', [Validators.required]],
refNo: ['', []]
});
I want other fields flagged as required to be 'un-required' if the refNo is provided by the user.
Here is how you can dynamically add or remove validator to some control
private addValidator(control, validator) {
let existingValidators = control.validator;
control.setValidators(Validators.compose([existingValidators, validator]));
control.updateValueAndValidity();
}
And to Remove validator
private removeRequiredValidator(control, otherValidators) {
control.clearValidators();
if (otherValidators) {
control.setValidators(otherValidators);
}
control.updateValueAndValidity();
}
Both the use of custom validators and setValidators
can get very complex very quickly. I prefer to configure the validators as they may be required and then conditionally enable or disable them.
Using exactly your code:
this.contractsFilter = this.fb.group({
selectedContractType: ['', [Validators.required]],
selectedYear: ['', [Validators.required]],
selectedPde: ['', [Validators.required]],
refNo: ['', []]
});
I would then subscribe to valueChanges
for refNo
:
this.contractsFilter.controls['refNo'].valueChanges.subscribe(value => {
if (value) { // There is a refNo specified
this.contractsFilter.controls['selectedContractType'].disable();
this.contractsFilter.controls['selectedYear'].disable();
this.contractsFilter.controls['selectedPde'].disable();
} else {
this.contractsFilter.controls['selectedContractType'].enable();
this.contractsFilter.controls['selectedYear'].enable();
this.contractsFilter.controls['selectedPde'].enable();
}
});
Now your validators are all specified in one consistent place, and you can still control whether the validators are executed or not.
Make use of setValidators
to set/unset validators for form controls
import {FormControl, Validators, FormGroup} from "@angular/forms";
onRefNoEntered() {
if(this.contractsFilter.controls['refNo'].value && this.contractsFilter.controls['refNo'].valid) {
this.contractsFilter.controls['selectedContractType'].setValidators(null);
this.contractsFilter.controls['selectedYear'].setValidators(null);
this.contractsFilter.controls['selectedPde'].setValidators(null);
}
else {
this.contractsFilter.controls['selectedContractType'].setValidators(Validators.required);
this.contractsFilter.controls['selectedYear'].setValidators(Validators.required);
this.contractsFilter.controls['selectedPde'].setValidators(Validators.required);
}
}
I faced a similar issue and, inspired by this solution , made something like this:
const control = new FormControl(null,
[this.conditionalValidator(Validators.required)],
[this.conditionalAsyncValidator(this.validatorService.customAsyncValidator(params))] );
private conditionalValidator(validator: ValidatorFn): ValidatorFn {
return (control: AbstractControl): ValidationErrors => {
if(this.condition) {
return null;
}
return validator(control);
}
}
private conditionalAsyncValidator(validator: AsyncValidatorFn): AsyncValidatorFn {
return (control: AbstractControl): Observable<ValidationErrors> | Promise<ValidationErrors> => {
if(this.condition2) {
return observableOf(null);
}
return validator(control);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.