【问题标题】:angular forms with multiple sync validators are valid despite it should be invalid具有多个同步验证器的角度形式是有效的,尽管它应该是无效的
【发布时间】:2018-02-08 22:06:56
【问题描述】:

我有 2 个表单控件。

当其中一个控件的值大于/小于另一个控件的值时,我会在我的 html 中得到正确的错误验证,并且 form.valid 为 TRUE。

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 分时,我得到:“不允许超过 100 分”并且 form.valid 为 FALSE,即正确!

但是……

当我现在将最差分数控制值更改为有效值时,之前的“最大错误”突然消失,form.valid 为 TRUE,这是不正确的!

除了使用 Compose 方法,我还尝试使用一组验证器,例如:

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

行为是一样的???

这里有什么问题?为什么将最差值控制值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

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

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

【问题讨论】:

  • 检查您的代码bestScoreControl.setErrors(null);。您正在重置相反控制的错误
  • 我调查了为什么我这样做了一次并得出了这个结论:当最差分数为 20 和最佳分数为 19 时,两者都显示红色错误消息。当我将最差分数降低到 18 时,最差分数的错误消息消失了,但最好分数的错误消息仍然存在。这意味着当我离开时......通过以最差分数进入 18 的无效表单状态不会触发/更新最佳分数控制的有效性。因此,我做了你所发现的。到目前为止效果很好,直到我尝试了多个验证器......
  • 看来我必须在对面控件的每个值更改时再次引入updateValueAndValidity()。
  • 最后我想我需要一种方法来清除/删除控件中的某个错误。当最好的分数更高时,我想删除最差的分数也可以,同时我不想删除最好的分数最高为 100 的错误。但是该功能/功能不存在:- (

标签: angular angular5 angular-forms


【解决方案1】:

尽管没有像为角形控制错误添加/删除特定错误这样的功能,但您可以自己实现它。

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

【讨论】:

  • 你的代码最酷的地方是删除操作符 ;-) 不知道它存在!
猜你喜欢
  • 2020-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-21
  • 2020-01-17
相关资源
最近更新 更多