获取FormGroup/FormControl中的验证程序

dev*_*054 17 typescript angular2-forms angular-material2 angular

我在我的应用程序中使用了Material 2,但在这个问题中,我想用Input专门解决问题.

正如您在API Reference中看到的那样,有一个名为的属性绑定required,在占位符中显示为星号.

所以,我想知道是否有办法检查表单控件是否在Angular中有一个特定的验证器,因为我真的不想为每个输入手动设置[required]="true/false"

我阅读了AbstractControl文档,但我没有找到任何相关内容.我遇到的hasError 方法(这具有讽刺意味的是没有记录无处 ......无论是在FormGroup也不FormControl也不AbstractControl),但是这不是我要找的.它只是检查表单控件是否有错误,但正如您可能已阅读过,我想检查控件是否有一些特定的验证器...

一些代码:

<md-input-container>
  <input placeholder="Placeholder" 
         mdInput [formControl]="anyCtrl" 
         [required]="anyCtrl.hasValidator('required')"> <!-- something like this -->
</md-input-container>
Run Code Online (Sandbox Code Playgroud)

我希望这个问题足够清楚.提前致谢.

joh*_*667 24

Angular并没有真正提供一个很好的,干净的方法,但它是可能的.我认为验证器存储在注入FormBuilder(NG_VALIDATORS)的服务中,我将研究劫持该服务或将其注入组件,但是现在这将起作用:

文档和源显示validator的成员AbstractControl类型来ValidatorFn.ValidatorFn不幸的是只是null打字,所以我们无法看到发生了什么.但是,在浏览生成的源并探测应用程序之后,似乎我们可以向此validators方法传递一个control参数,该参数将返回该控件上存在的所有验证器的对象,而不管它是否正在通过.

奇怪的是,这只适用于FormControl自身,而不是FormGroup(在成员上FormGroup,validators成员不是一个功能,而且总是null在我的测试中).编译好的JS说这个函数需要一个control参数; 我已经尝试传入FormControl引用,但据我所知它只会返回控件上的验证器,只要此参数不为null.

在FormControl上获取验证器

// in the constructor
this.myForm = this.formBuilder.group({
  'anyCtrl': ['', Validators.required],
  'anotherCtrl': ['', Validators.compose([Validators.required, Validators.email])]
});

// later on 
let theValidators = this.myForm.controls['anyCtrl'].validator('');
console.log(theValidators) // -> {required: true};

let otherValidators = this.myForm.controls['anotherCtrl'].validator('');
console.log(otherValidators); // -> {required: true, email: true}
Run Code Online (Sandbox Code Playgroud)

更容易抓住:

public hasValidator(control: string, validator: string): boolean {
  return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
 // returns true if control has the validator
}
Run Code Online (Sandbox Code Playgroud)

在你的标记中:

<md-input-container>
  <input placeholder="Placeholder" 
         mdInput [formControl]="anyCtrl" 
         [required]="hasValidator('anyCtrl', 'email')">
</md-input-container>
Run Code Online (Sandbox Code Playgroud)

Validators.required的特例

required验证器的快捷方式.的[required]结合实际上是实例RequiredValidator 指令(源极/ forms.js的线5022).该指令实际上会将requiredValidator 添加到其中FormControl.这相当于增加了Validators.requiredFormGroup初始化时.因此,将bound属性设置为false required将从该控件中删除Validator,反之亦然......无论哪种方式,该指令都会影响该FormControl.required值,因此将其绑定到它更改的属性并不会真正起作用.

唯一的区别是该[required]指令将星号添加到占位符而Validators.required不是.

我将继续关注NG_VALIDATORS,但我希望现在有所帮助!

  • AFAIK `hasValidator()` 方法仅适用于“失败”的验证器(即,具有值 '' (emtpy) 的控件上的必需验证器)。因为如果他们通过他们返回null。解决此问题的一种方法是设置该值,使其始终失败并在之后恢复该值。我将发布一个答案作为后续,因为很难将代码放入评论中。 (4认同)
  • 啊,关于你的最后一句话:我知道**差异**只是*星号*这就是我想要的原因:)我希望有一天Material 2团队实施一个解决方案,添加星号寻找反应形式,无需在HTML本身中设置`required`.:) (3认同)
  • 您好,@ joh04667,首先,我只想说:**谢谢**.我刚刚测试了你的解决方案[**这里**](https://plnkr.co/edit/d2nprY4KTf4P9V3sIwrA)它似乎工作.但是,值得一提的是它会抛出错误如果你有一个没有验证器的`control`,换句话说,`validators`是*null*.测试它[**这里**](https://plnkr.co/edit/wsv1wyDOMU57vBpu8V6s).那说,多谢一次. (2认同)
  • 这有效,但似乎只表明验证器失败。例如,当控件具有预设值且需要时。用这个就不会这样说。我使用了一种解决方法,存储该值,将其设置为 null,执行此检查,然后恢复该值。 (2认同)

pas*_*sek 21

Angular v12.2 推出hasValidator()https://github.com/angular/angular/pull/42838

例子:this.formGroup.controls['anyCtrl'].hasValidator(Validators.required)

您还可以稍后以编程方式添加或删除验证器。参见addValidators()removeValidators()、 和其他。

https://angular.io/api/forms/AbstractControl#hasValidator

  • “提供的验证器必须是对所提供的完全相同的函数的引用。” 这也使得它毫无用处。如果我设置 Validators.min(0),检查 control.hasValidator(Validators.min(0)) 返回 false,仅验证相同的验证实例返回 true。 (11认同)

Kyr*_*ous 7

如果你想检查一个控制器是否有特定的验证器,对于 Angular 12.2+ 来说非常简单

例如,

let controller = new FormControl('', [Validators.required])
console.log(controller.hasValidator(Validators.required))//true
Run Code Online (Sandbox Code Playgroud)

但是,这不适用于Validators.minLength()Validators.maxLength()Validators.min()Validators.max任何需要参数的验证器。

为了使其工作,您需要为该验证器创建一个引用,并将该引用添加到表单控制器验证器和函数中hasValidator

例如,

const minLengthValidator = Validators.minLength(60);
let controller = new FormControl('', [minLengthValidator])
console.log(controller.hasValidator(minLengthValidator)) //true
Run Code Online (Sandbox Code Playgroud)

但如果你执行以下操作,你会得到错误的结果:

let controller = new FormControl('', [ Validators.minLength(60)])
console.log(controller.hasValidator( Validators.minLength(60))) //false
Run Code Online (Sandbox Code Playgroud)


Han*_*kCa 5

这个答案是@joh04667's的延续。他们写:

public hasValidator(control: string, validator: string): boolean {
  return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
 // returns true if control has the validator
}
Run Code Online (Sandbox Code Playgroud)

然而没有AbstractControls.validators()方法。我假设AbstractControls.validator()是这个意思。

hasValidator()方法仅适用于“失败”的验证器(例如,控件上具有值“(空)”的必需验证器)。因为如果他们通过他们返回null。解决此问题的一种方法是设置该值,使其始终失败并在之后恢复该值。

public hasValidator(control: string, validator: string): boolean {
    let control: AbstractControl = this.myForm.controls[control];
    let lastValue: any = control.value;
    switch(validator) {
        case 'required':
            control.setValue('');  // as is appropriate for the control
        case 'pattern':
            control.setValue('3'); // given you have knowledge of what the pattern is - say its '\d\d\d'
        ....
    }
    let hasValidator: boolean = !!control.validator(control).hasOwnProperty(validator);

    control.setValue(lastValue);
    return hasValidator;
}
Run Code Online (Sandbox Code Playgroud)

这是非常可怕的。这就引出了一个问题——为什么没有AbstractControl.getValidators(): ValidatorFn[]|null

隐藏这个的动机是什么?也许他们担心有人可能会放入他们的代码:

...
secretPassword: ['', [Validators.pattern('fjdfjafj734738&UERUEIOJDFDJj')]
...
Run Code Online (Sandbox Code Playgroud)


Dil*_*age 5

没有直接或干净的方法可以做到这一点。这是我遇到的最干净、有效的方法。使用最新版本的Angular v10.2.0进行测试(截至今天)

导入这些

import {AbstractControl, FormControl, Validators} from '@angular/forms';
Run Code Online (Sandbox Code Playgroud)

定义您的控制

anyCtrl = new FormControl('', [Validators.required]);
Run Code Online (Sandbox Code Playgroud)

添加这个方法

  public hasRequiredField = (abstractControl: AbstractControl): boolean => {
    if (abstractControl.validator) {
      const validator = abstractControl.validator({}as AbstractControl);
      if (validator && validator.required) {
        return true;
      }
    }
    return false;
  }
Run Code Online (Sandbox Code Playgroud)

如何从 HTML 调用此方法

<input placeholder="Placeholder" [formControl]="anyCtrl" [required]="hasRequiredField(anyCtrl)">
Run Code Online (Sandbox Code Playgroud)

在构造函数或 ngOnInit 中从 Typescript 文件(逻辑)调用它

constructor() {
  console.log(this.hasRequiredField(this.anyCtrl)); // true, false if Validators array does not contain Validators.required
}
Run Code Online (Sandbox Code Playgroud)