为什么我应该使用Validators.compose()?

54

我有一个字段需要使用多个验证器进行验证。
使用模块化驱动的方法,代码看起来像这样:

this.exampleForm = this.fb.group({
  date_start : [
    '',
    Validators.compose([
      Validators.required,
      Validators.pattern("[0-9]{2}-[0-9]{2}-[0-9]{4}")
    ])]
})

但我也可以不使用 Validators.compose() 来编写:

this.exampleForm = this.fb.group({
  date_start : [
    '',
    [
      Validators.required,
      Validators.pattern("[0-9]{2}-[0-9]{2}-[0-9]{4}")
    ]
  ]
})

它完全有效。个人而言,我更喜欢第二个版本(没有 compose ),代码更少,可读性更好。这就引出了一个问题,为什么我应该使用Validators.compose()?


1
我猜这主要是出于历史原因。 - Günter Zöchbauer
哈哈,我猜...真的很奇怪,到目前为止我在各种地方(视频、博客等)都发现了那个历史方法,然后突然在 Angular Cookbook 上发现我不需要它。 - Mihailo
12
2016年7月/8月,表单模块进行了大规模的修改,compose() 的要求被取消了,但我猜他们保留了它,以免不必要地破坏现有代码和困惑用户。 - Günter Zöchbauer
哦,我猜想大概是这样。好的,谢谢你提供的信息。 :) - Mihailo
4
嗯...在FormArray上仍然需要添加多个验证器(因为它的构造函数只接受单个ValidatorFn而不是数组)。只有当他们合并此拉取请求时才不必这样做。 - developer033
2个回答

27

当我们创建 new FormControl/FormGroup/FormArray(AbstractControl) 时,会调用 coerceToValidator

function coerceToValidator(
    validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null): ValidatorFn|
    null {
  const validator =
      (isOptionsObj(validatorOrOpts) ? (validatorOrOpts as AbstractControlOptions).validators :
                                       validatorOrOpts) as ValidatorFn |
      ValidatorFn[] | null;

  return Array.isArray(validator) ? composeValidators(validator) : validator || null;
}

export function composeValidators(validators: Array<Validator|Function>): ValidatorFn|null {
  return validators != null ? Validators.compose(validators.map(normalizeValidator)) : null;
}

在将其传递给AbstractControl之前,没有必要组合验证器。

6/13/16添加了feat(forms): compose validator fns automatically if arrays从现在开始,Validators.compose用于向后兼容。


嘿,fns是什么意思?抱歉,我不明白这个缩写的含义。 - undefined

25

我知道这是一个比较旧的问题,但最近的搜索中它出现了。

你可能想使用Validators.compose()的主要原因是重用多个验证器。假设你想检查一个值是否在0到100之间。第一次,你需要写:

this.form = this.fb.group({
  foo: [ 0, [ Validators.min(0), Validators.max(100)]]
});

现在假设你想在应用程序中的多个位置执行此操作。为了避免代码重复,您可以通过简单地从现有验证器组合它来创建自己的验证器,然后将其公开并在需要时重复使用:

// custom-validators.ts
import { Validators } from '@angular/forms';
export class CustomValidators {
  readonly betweenZeroHundred = Validators.compose([
    Validators.min(0),
    Validators.max(100),
  ]);
}

// form1 
this.form = this.fb.group({
  foo: [ 0, [CustomValidators.betweenZeroHundred()]]
});

// form2
this.form = this.fb.group({
  bar: [ 100, [CustomValidators.betweenZeroHundred()]]
});

现在,使用扩展运算符,你可以在不使用compose()的情况下实现类似的结果:

export class CustomValidators {
  readonly betweenZeroHundred = [Validators.min(0), Validators.max(100)];
}

this.form = this.fb.group({
  bar: [ 100, [...CustomValidators.betweenZeroHundred, Validators.required]]
});


最终,关键在于哪种方法更适合您的团队和情况。


3
为什么不在整个代码库中重复使用一个数组?我认为没有理由使用 Validators.compose - manymanymore
那也是我的第一反应 - 只需使用数组即可。 - Antoniossss
我会选择使用数组和扩展运算符,因为它清楚地展示了正在发生的事情,无需来回导航或查阅另一个函数的文档。 - mrmoree

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接