angular 具有多个同步验证器的表单是有效的,尽管它应该是无效的

angular forms with multiple sync validators are valid despite it should be invalid

我有 2 个 FormControl。

当其中一个控件的值比另一个控件的值 greater/small 时,我在 html 中得到了正确的错误验证,并且 form.valid 为真。

this.bestGradeScoresFormControl.setValidators(bestScoresGreaterThanWorstScoresValidator(this.worstGradeScoresFormControl), 
Validators.max(100)]);
this.worstGradeScoresFormControl.setValidators(worstScoresSmallerThanBestScoresValidator(this.bestGradeScoresFormControl));

然后我使用 Compose 函数将 Validators.max(100) 添加到 bestScores 控件中:

this.bestGradeScoresFormControl.setValidators(Validators.compose(
[bestScoresGreaterThanWorstScoresValidator(this.worstGradeScoresFormControl), Validators.max(100)]));
this.worstGradeScoresFormControl.setValidators(worstScoresSmallerThanBestScoresValidator(this.bestGradeScoresFormControl));

当我为最佳分数控制设置 101 个分数时,我得到:'More than 100 scores are not allowed' 并且 form.valid 为 FALSE,这是正确的!

但是...

当我现在将最差分数控制值更改为有效值时,之前的 'max error' 突然消失并且 form.valid 为真,那是不正确的!

我没有使用 Compose 方法,而是尝试使用验证器数组,例如:

this.bestGradeScoresFormControl.setValidators([bestScoresGreaterThanWorstScoresValidator(this.worstGradeScoresFormControl), Validators.max(100)]);
  this.worstGradeScoresFormControl.setValidators(worstScoresSmallerThanBestScoresValidator(this.bestGradeScoresFormControl));

行为相同???

这里有什么问题?为什么将 worstScore 控制值 form.valid 值从 FALSE 更改为 TRUE?

export const bestScoresGreaterThanWorstScoresValidator = (worstScoreControl: FormControl): ValidatorFn => {
  return (control: FormControl): { [key: string]: boolean } => {
    if (control.value > worstScoreControl.value) {
      worstScoreControl.setErrors(null);
      control.setErrors(null);
    }
    else {
      worstScoreControl.setErrors({ "bestScoresGreaterThanWorstScores": true });
      return { 'bestScoresGreaterThanWorstScores': true };
    }
  };
}

export const worstScoresSmallerThanBestScoresValidator = (bestScoreControl: FormControl): ValidatorFn => {
  return (control: FormControl): { [key: string]: boolean } => {
    if (control.value < bestScoreControl.value) {
      bestScoreControl.setErrors(null);
      control.setErrors(null);
    }
    else {
      bestScoreControl.setErrors({ "worstScoresSmallerThanBestScores": true });
      return { 'worstScoresSmallerThanBestScores': true };
    }
  };
}

更新

我在这里放了一个plunkr来说明问题:

https://plnkr.co/edit/ygiVNtPImkMveLGogTk2?p=preview

在我看来,解决方案不能是我在整个表单上创建一个唯一的自定义验证器,因为我希望所有自定义验证器都有自己的验证器 class/function。

如果您根据我的 plunkr 代码做出解决方案,那么赏金就是您的:-)

尽管没有 add/remove 针对 angular 表单控件错误的特定错误这样的功能,但您可以自己实现它。

function addError(control: AbstractControl, errorKey: string) {
  const errors = control.errors || {};
  errors[errorKey] = true;

  control.setErrors(errors);
}

function removeError(control: AbstractControl, errorKey: string) {
  const errors = control.errors || {};
  delete errors[errorKey];

  control.setErrors(Object.keys(errors).length ? errors : null)
}

现在只需在自定义验证器中需要时添加或删除错误即可:

bestScoresGreaterThanWorstScoresValidator

export const bestScoresGreaterThanWorstScoresValidator = 
                              (worstScoreControl: FormControl): ValidatorFn => {
  return (control: FormControl): { [key: string]: boolean } => {

    if (control.value > worstScoreControl.value) {
      removeError(worstScoreControl, 'worstScoresSmallerThanBestScores')
      return null;
    }
    else {
      addError(worstScoreControl, 'worstScoresSmallerThanBestScores');
      return { 'bestScoresGreaterThanWorstScores': true };
    }

  };
}

worstScoresSmallerThanBestScoresValidator

export const worstScoresSmallerThanBestScoresValidator = 
                               (bestScoreControl: FormControl): ValidatorFn => {
  return (control: FormControl): { [key: string]: boolean } => {

    if (control.value < bestScoreControl.value) {
      removeError(bestScoreControl, 'bestScoresGreaterThanWorstScores')
      return null;
    }
    else {
      addError(bestScoreControl, 'bestScoresGreaterThanWorstScores');
      return { 'worstScoresSmallerThanBestScores': true };
    }
  };
}

ng-run example