获取 FormGroup/FormControl 中的验证者
Get validators present in FormGroup/FormControl
我在我的应用程序中使用 Material 2,但在这个问题中我想解决一个问题,特别是 Input。
正如您在 API 参考资料 中看到的那样,有一个名为 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>
我希望问题足够清楚。提前致谢。
Angular 并没有真正提供一个很好的、干净的方法来做到这一点,但这是可能的。我认为验证器存储在注入到 FormBuilder(NG_VALIDATORS
) 的服务中,我将研究劫持该服务或将其注入组件,但现在这可行:
docs 和来源显示 AbstractControl
上的 validator
成员键入 ValidatorFn
。 ValidatorFn
不幸的是只有一个 null
类型,所以我们看不到发生了什么。然而,在查看生成的源代码并探测一个应用程序之后,似乎我们可以向这个 validators
方法传递一个 control
参数,这将 return 该控件上存在的所有验证器的对象,不管是否通过。
奇怪的是,这个只适用于FormControl
本身而不是FormGroup
(在FormGroup
,validators
成员不是函数,在我的测试中总是 null
)。编译后的 JS 说这个函数需要一个 control
参数;我已经尝试传递 FormControl
引用,但据我所知,只要此参数不为 null,它只会 return 控件上的验证器。
在 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}
更容易抓取:
public hasValidator(control: string, validator: string): boolean {
return !!this.myForm.controls[control].validator(control).hasOwnProperty(validator);
// returns true if control has the validator
}
并在您的标记中:
<md-input-container>
<input placeholder="Placeholder"
mdInput [formControl]="anyCtrl"
[required]="hasValidator('anyCtrl', 'email')">
</md-input-container>
Validators.required
的特例
required
验证器有一个快捷方式。 [required]
绑定实际上是 RequiredValidator
指令 的一个实例(source/forms.js 的第 5022 行)。该指令实际上会将 required
验证程序添加到它所在的 FormControl
中。它相当于在初始化时将 Validators.required
添加到 FormGroup
。因此,将绑定 属性 设置为 false 将从该控件中删除 required
验证器,反之亦然......无论哪种方式,该指令都会影响 FormControl.required
值,因此将其绑定到 属性 它的改变不会有太大作用。
唯一的区别是 [required]
指令将星号添加到占位符,而 Validators.required
则没有。
我将继续研究 NG_VALIDATORS
,但我希望这对现在有所帮助!
此答案是 的延续。他们写道:
public hasValidator(control: string, validator: string): boolean {
return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
// returns true if control has the validator
}
但是没有AbstractControls.validators()
方法。我假设 AbstractControls.validator()
是有意的。
hasValidator()
方法仅适用于 'fail' 的验证器(例如,控件上值为“”(空)的必需验证器)。因为如果他们通过了他们 return 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;
}
这太可怕了。这就引出了一个问题——为什么没有AbstractControl.getValidators(): ValidatorFn[]|null
?
隐藏这个的动机是什么?也许他们担心有人可能会输入他们的代码:
...
secretPassword: ['', [Validators.pattern('fjdfjafj734738&UERUEIOJDFDJj')]
...
我将 joh04667 和 HankCa 的代码调整为:
export const hasValidator = (form: FormGroup, controlPath: string, validator: string): boolean => {
const control = form.get(controlPath);
const validators = control.validator(control);
return !!(validators && validators.hasOwnProperty(validator));
};
我将其存储在一个名为 util.ts 的文件中,并导入到包含如下形式的组件中:
import * as util from '@app/shared/util';
并在 class 中定义 util:
public util = util;
像这样将指令添加到您的输入组件:
[required]="util.hasValidator(myForm, 'path.to.control', 'required')"
根据 mtinner 的推荐 https://github.com/angular/angular/issues/13461#issuecomment-340368046 我们构建了自己的指令来相应地标记必填字段。
@Directive({
selector: '[mandatoryField]'
})
export class MandatoryFieldDirective implements OnInit {
hasRequiredField(abstractControl: AbstractControl) {
if (abstractControl.validator) {
const validator = abstractControl.validator({} as AbstractControl);
if (validator && validator.required) {
return true;
}
}
return false;
}
ngOnInit() {
const required = this.hasRequiredField(this.ngControl.control);
if (required) {
this.renderer.setAttribute(this.elementRef.nativeElement, 'required', '');
if (this.parentFormField && this.parentFormField._elementRef) { // required for Angular Material form-fields
this.renderer.setAttribute(this.parentFormField._elementRef.nativeElement, 'required', '');
}
}
}
constructor(
private ngControl: NgControl, @Optional() private parentFormField: MatFormField,
public renderer: Renderer2, public elementRef: ElementRef
) { }
}
该指令设置了一个 'required' 属性。该属性可以通过 CSS 寻址。该指令适用于正常的 HTML 输入标签以及 Angular Material 表单字段。要使用 Angular Material,我们必须添加一些变通方法,因为必须在封闭的表单字段标签上设置 'required' 属性;不仅在实际的输入字段上。因此,父组件传递给指令构造函数。
<mat-form-field class="date-picker-form">
<input matInput class="label-value" [formControlName]="controlName" mandatoryField [matDatepicker]="picker">
<mat-datepicker #picker class="calendar"></mat-datepicker>
</mat-form-field>
没有直接或干净的方法可以做到这一点。这是我遇到的最干净的方法,有效。使用最新版本 Angular v10.2.0 进行测试(截至今天)
导入这些
import {AbstractControl, FormControl, Validators} from '@angular/forms';
定义您的控件
anyCtrl = new FormControl('', [Validators.required]);
添加此方法
public hasRequiredField = (abstractControl: AbstractControl): boolean => {
if (abstractControl.validator) {
const validator = abstractControl.validator({}as AbstractControl);
if (validator && validator.required) {
return true;
}
}
return false;
}
如何从 HTML
中调用此方法
<input placeholder="Placeholder" [formControl]="anyCtrl" [required]="hasRequiredField(anyCtrl)">
从构造函数或 ngOnInit 中的 Typescript 文件(逻辑)调用它
constructor() {
console.log(this.hasRequiredField(this.anyCtrl)); // true, false if Validators array does not contain Validators.required
}
请务必牢记,使用 setValidator 方法将覆盖您现有的验证器,因此您需要为要重置的控件包含所有 need/want 验证器。
control.setValidators([myCustomValidator(owner)]);
没有这么干净的方法,但你总是可以通过
让验证器出现在任何表单组或表单控件中
this.form.controls[key].validator
然后添加您的自定义控件,我们可以这样做
control.setValidators([control.validator, myCustomValidator(owner)]);
这将使我们能够重用现有的验证器以及我们新的自定义验证器
从 Angular v12.2
开始 AbstractControl
应该有 a new method:
hasValidator(validator: ValidatorFn): boolean;
Angular v12.2 引入 hasValidator()
: https://github.com/angular/angular/pull/42838
示例:this.formGroup.controls['anyCtrl'].hasValidator(Validators.required)
您也可以稍后以编程方式添加或删除验证器。请参阅 addValidators()
、removeValidators()
和其他内容。
使用最新的 Angular 版本 v12.2 和 hasValidator,您可以像这样创建管道:
@Pipe({
name: 'hasRequiredValidator',
})
export class HasRequiredValidatorPipe implements PipeTransform {
transform(value: AbstractControl | null, controlName?: string): boolean {
const control = controlName ? value?.get(controlName) : value;
return !!control?.hasValidator(Validators.required);
}
}
并在 html 模板中
<input [required]="form | hasRequiredValidator: 'controlName'">
或者
<input [required]="form.get('controlName') | hasRequiredValidator">
如果你想检查一个controller是否有特定的validators,对于angular 12.2+
来说非常简单
例如,
let controller = new FormControl('', [Validators.required])
console.log(controller.hasValidator(Validators.required))//true
但是,这不适用于 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
但是如果你执行以下操作,你会得到 false:
let controller = new FormControl('', [ Validators.minLength(60)])
console.log(controller.hasValidator( Validators.minLength(60))) //false
我在我的应用程序中使用 Material 2,但在这个问题中我想解决一个问题,特别是 Input。
正如您在 API 参考资料 中看到的那样,有一个名为 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>
我希望问题足够清楚。提前致谢。
Angular 并没有真正提供一个很好的、干净的方法来做到这一点,但这是可能的。我认为验证器存储在注入到 FormBuilder(NG_VALIDATORS
) 的服务中,我将研究劫持该服务或将其注入组件,但现在这可行:
docs 和来源显示 AbstractControl
上的 validator
成员键入 ValidatorFn
。 ValidatorFn
不幸的是只有一个 null
类型,所以我们看不到发生了什么。然而,在查看生成的源代码并探测一个应用程序之后,似乎我们可以向这个 validators
方法传递一个 control
参数,这将 return 该控件上存在的所有验证器的对象,不管是否通过。
奇怪的是,这个只适用于FormControl
本身而不是FormGroup
(在FormGroup
,validators
成员不是函数,在我的测试中总是 null
)。编译后的 JS 说这个函数需要一个 control
参数;我已经尝试传递 FormControl
引用,但据我所知,只要此参数不为 null,它只会 return 控件上的验证器。
在 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}
更容易抓取:
public hasValidator(control: string, validator: string): boolean {
return !!this.myForm.controls[control].validator(control).hasOwnProperty(validator);
// returns true if control has the validator
}
并在您的标记中:
<md-input-container>
<input placeholder="Placeholder"
mdInput [formControl]="anyCtrl"
[required]="hasValidator('anyCtrl', 'email')">
</md-input-container>
Validators.required
的特例required
验证器有一个快捷方式。 [required]
绑定实际上是 RequiredValidator
指令 的一个实例(source/forms.js 的第 5022 行)。该指令实际上会将 required
验证程序添加到它所在的 FormControl
中。它相当于在初始化时将 Validators.required
添加到 FormGroup
。因此,将绑定 属性 设置为 false 将从该控件中删除 required
验证器,反之亦然......无论哪种方式,该指令都会影响 FormControl.required
值,因此将其绑定到 属性 它的改变不会有太大作用。
唯一的区别是 [required]
指令将星号添加到占位符,而 Validators.required
则没有。
我将继续研究 NG_VALIDATORS
,但我希望这对现在有所帮助!
此答案是
public hasValidator(control: string, validator: string): boolean {
return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
// returns true if control has the validator
}
但是没有AbstractControls.validators()
方法。我假设 AbstractControls.validator()
是有意的。
hasValidator()
方法仅适用于 'fail' 的验证器(例如,控件上值为“”(空)的必需验证器)。因为如果他们通过了他们 return 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;
}
这太可怕了。这就引出了一个问题——为什么没有AbstractControl.getValidators(): ValidatorFn[]|null
?
隐藏这个的动机是什么?也许他们担心有人可能会输入他们的代码:
...
secretPassword: ['', [Validators.pattern('fjdfjafj734738&UERUEIOJDFDJj')]
...
我将 joh04667 和 HankCa 的代码调整为:
export const hasValidator = (form: FormGroup, controlPath: string, validator: string): boolean => {
const control = form.get(controlPath);
const validators = control.validator(control);
return !!(validators && validators.hasOwnProperty(validator));
};
我将其存储在一个名为 util.ts 的文件中,并导入到包含如下形式的组件中:
import * as util from '@app/shared/util';
并在 class 中定义 util:
public util = util;
像这样将指令添加到您的输入组件:
[required]="util.hasValidator(myForm, 'path.to.control', 'required')"
根据 mtinner 的推荐 https://github.com/angular/angular/issues/13461#issuecomment-340368046 我们构建了自己的指令来相应地标记必填字段。
@Directive({
selector: '[mandatoryField]'
})
export class MandatoryFieldDirective implements OnInit {
hasRequiredField(abstractControl: AbstractControl) {
if (abstractControl.validator) {
const validator = abstractControl.validator({} as AbstractControl);
if (validator && validator.required) {
return true;
}
}
return false;
}
ngOnInit() {
const required = this.hasRequiredField(this.ngControl.control);
if (required) {
this.renderer.setAttribute(this.elementRef.nativeElement, 'required', '');
if (this.parentFormField && this.parentFormField._elementRef) { // required for Angular Material form-fields
this.renderer.setAttribute(this.parentFormField._elementRef.nativeElement, 'required', '');
}
}
}
constructor(
private ngControl: NgControl, @Optional() private parentFormField: MatFormField,
public renderer: Renderer2, public elementRef: ElementRef
) { }
}
该指令设置了一个 'required' 属性。该属性可以通过 CSS 寻址。该指令适用于正常的 HTML 输入标签以及 Angular Material 表单字段。要使用 Angular Material,我们必须添加一些变通方法,因为必须在封闭的表单字段标签上设置 'required' 属性;不仅在实际的输入字段上。因此,父组件传递给指令构造函数。
<mat-form-field class="date-picker-form">
<input matInput class="label-value" [formControlName]="controlName" mandatoryField [matDatepicker]="picker">
<mat-datepicker #picker class="calendar"></mat-datepicker>
</mat-form-field>
没有直接或干净的方法可以做到这一点。这是我遇到的最干净的方法,有效。使用最新版本 Angular v10.2.0 进行测试(截至今天)
导入这些
import {AbstractControl, FormControl, Validators} from '@angular/forms';
定义您的控件
anyCtrl = new FormControl('', [Validators.required]);
添加此方法
public hasRequiredField = (abstractControl: AbstractControl): boolean => {
if (abstractControl.validator) {
const validator = abstractControl.validator({}as AbstractControl);
if (validator && validator.required) {
return true;
}
}
return false;
}
如何从 HTML
中调用此方法<input placeholder="Placeholder" [formControl]="anyCtrl" [required]="hasRequiredField(anyCtrl)">
从构造函数或 ngOnInit 中的 Typescript 文件(逻辑)调用它
constructor() {
console.log(this.hasRequiredField(this.anyCtrl)); // true, false if Validators array does not contain Validators.required
}
请务必牢记,使用 setValidator 方法将覆盖您现有的验证器,因此您需要为要重置的控件包含所有 need/want 验证器。
control.setValidators([myCustomValidator(owner)]);
没有这么干净的方法,但你总是可以通过
让验证器出现在任何表单组或表单控件中 this.form.controls[key].validator
然后添加您的自定义控件,我们可以这样做
control.setValidators([control.validator, myCustomValidator(owner)]);
这将使我们能够重用现有的验证器以及我们新的自定义验证器
从 Angular v12.2
开始 AbstractControl
应该有 a new method:
hasValidator(validator: ValidatorFn): boolean;
Angular v12.2 引入 hasValidator()
: https://github.com/angular/angular/pull/42838
示例:this.formGroup.controls['anyCtrl'].hasValidator(Validators.required)
您也可以稍后以编程方式添加或删除验证器。请参阅 addValidators()
、removeValidators()
和其他内容。
使用最新的 Angular 版本 v12.2 和 hasValidator,您可以像这样创建管道:
@Pipe({
name: 'hasRequiredValidator',
})
export class HasRequiredValidatorPipe implements PipeTransform {
transform(value: AbstractControl | null, controlName?: string): boolean {
const control = controlName ? value?.get(controlName) : value;
return !!control?.hasValidator(Validators.required);
}
}
并在 html 模板中
<input [required]="form | hasRequiredValidator: 'controlName'">
或者
<input [required]="form.get('controlName') | hasRequiredValidator">
如果你想检查一个controller是否有特定的validators,对于angular 12.2+
来说非常简单例如,
let controller = new FormControl('', [Validators.required])
console.log(controller.hasValidator(Validators.required))//true
但是,这不适用于 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
但是如果你执行以下操作,你会得到 false:
let controller = new FormControl('', [ Validators.minLength(60)])
console.log(controller.hasValidator( Validators.minLength(60))) //false