5

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.

0

4 Answers 4

4

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();
  }
Sign up to request clarification or add additional context in comments.

Comments

3

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.

Comments

0

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);
        }
}

Comments

0

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);
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.