0

I have form Array , which controls has to be required , based on a variable ,now I wrote custom validator like below

  recurringValidator(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      if (!control.value) {
        return null;
      }
      if (this.myVariable === 'constant1') {
        return Validators.required;
      }
      return null;
    };
  }

now this will check the value of the 'myVariable' and put required but somehow its not working , I am adding this custom validators like below

const fbGroup = this.fb.group({
  recurringControl1: this.fb.control('', [this.recurringValidator()]),
  recurringControl2: this.fb.control('', [this.recurringValidator()]),
  recurringControl3: this.fb.control('', [this.recurringValidator()])
});

   this.myForm = this.fb.group({
      control1: fb.control('', [this.recurringValidator()]),
      groupcontrol1: fb.array([])
    });

when I click on submit , form is valid when even myVariable value is 'constant1' . any suggestion or modifications please .

here is the stackblitz link https://stackblitz.com/edit/angular-form-array-validators?

2
  • any special reason you are return Validators.requred from async validator function ? @Shaswata Commented May 26, 2021 at 9:58
  • depnding on the variable value , it can be not required also , Commented May 26, 2021 at 10:00

2 Answers 2

1

You are passing the validator reference instead of executing and returning the value. If you were to use the validator directly, that would be the correct way to do it, but since you are using your custom validator, the validator will be called by Angular (your validator) but for the required validator, you are the one who need to invoke it, so try replacing:

recurringValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!control.value) {
      return null;
    }
    if (this.myVariable === 'constant1') {
      return Validators.required;
    }
    return null;
  };
}

To:

recurringValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    // if (!control.value) {
    //   return null;
    // }
    if (this.myVariable === 'constant1') {
      // Invoking the validator ourselves
      return Validators.required(control);
    }
    return null;
  };
}

Also, I don't see the need for the first condition !control.value, that will always return null for empty values no matter the content of myVariable, so I commented out.

StackBlitz

Sign up to request clarification or add additional context in comments.

Comments

1

You can not return a Validator, else an object and make a custom validator

If your variable not change with the time you can do

recurringValidator(necesary:boolean): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      if (control.value) { //<--if has any value return null
        return null;
      }
      if (necesary) {
        return {required:true} //<--see that you return an object, NOT Validators.required
      }
      return null;
    };
  }

And you use

control=new FormControl(null,this.recurringValidator(this.myVariable!='constant1'))

See that, if you change the value of myVariableafter create the formControl, not work, the validator get the actual value of the variable

If you need take account the variable and the variable change in the time you need use "bind(this)" when you create the form

recurringValidator(): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
      if (control.value) {
        return null;
      }
      if (this.myVariable === 'constant1') {
        return {required:true} //<--see that you return an object, NOT Validators.required
      }
      return null;
    };
  }

And use

control=new FormControl(null,this.recurringValidator().bind(this))

In this case, when you change the variable don't forget updateAndValidity the control, e.g.

<button (click)="myVariable=!myVariable;
                control.updateValueAndValidity()">
    click
</button>

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.