typescript 获取存在于 FormGroup/FormControl 中的验证器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43838108/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get validators present in FormGroup/FormControl
提问by dev_054
I'm using Material 2 in my app, but in this question I want to solve a problem specifically with Input.
我在我的应用程序中使用 Material 2,但在这个问题中,我想解决一个专门使用Input的问题。
As you can see in API Referencethere's a property bind called required
, which shows as asterisk in the placeholder.
正如您在API 参考中看到的,有一个名为 的属性绑定required
,它在占位符中显示为星号。
So, I'm wondering if there's a way to check if the form control has an specific validator in Angular, because I really don't want to set manually for each input [required]="true/false"
所以,我想知道是否有办法检查表单控件在Angular 中是否有特定的验证器,因为我真的不想为每个输入手动设置[required]="true/false"
I read the AbstractControldocs and I didn't find anything about it. I've encountered the hasError
method(which ironicallyisn't documented in nowhere... neither in FormGroup nor in FormControl nor in AbstractControl), however this is not what I'm looking for. It just checks if the form control has the error, but as you may have read, I want to check if the control has some specific validators...
我阅读了AbstractControl文档,但没有找到任何相关信息。我遇到过这种hasError
方法(具有讽刺意味的是,它没有在任何地方都有记录......无论是在 FormGroup 中,还是在 FormControl 中,也不是在 AbstractControl 中),但这不是我正在寻找的。它只是检查表单控件是否有错误,但正如您可能已经读过的,我想检查控件是否有一些特定的验证器......
Some code:
一些代码:
<md-input-container>
<input placeholder="Placeholder"
mdInput [formControl]="anyCtrl"
[required]="anyCtrl.hasValidator('required')"> <!-- something like this -->
</md-input-container>
I hope the question is clear enough. Thanks in advance.
我希望这个问题足够清楚。提前致谢。
回答by joh04667
Angular doesn't really provide a great, clean way to do this, but it is possible. I think the validators are stored in a service that is injected into the FormBuilder(NG_VALIDATORS
), and I'm going to look into hiHymaning that service or injecting it into a component, but for now this will work:
Angular 并没有真正提供一种很好的、干净的方法来做到这一点,但它是可能的。我认为验证器存储在注入 FormBuilder( NG_VALIDATORS
) 的服务中,我将研究劫持该服务或将其注入组件,但现在这将起作用:
The docsand the source show a validator
member on AbstractControl
typed to ValidatorFn
. ValidatorFn
unfortunately simply has a null
typing, so we can't see what's going on. However, after poking through the generated source and probing an app, it seems we can pass this validators
method a control
parameter, which will return an object of all validators present on that control, regardless of whether or not it's passing.
该文档和源显示validator
的成员AbstractControl
类型来ValidatorFn
。ValidatorFn
不幸的是只有null
打字,所以我们看不到发生了什么。然而,在查看生成的源代码并探测应用程序之后,似乎我们可以向此validators
方法传递一个control
参数,该参数将返回该控件上存在的所有验证器的对象,无论它是否通过。
Strangely, this onlyworks on the FormControl
itself and not the FormGroup
(on the FormGroup
, the validators
member is not a function and was always null
in my testing). The compiled JS says this function takes a control
parameter; I've tried passing in FormControl
references but as far as I can tell it will just return the validators on the control as long as this parameter is not null.
奇怪的是,这仅适用于FormControl
本身而不适用于FormGroup
(在 上FormGroup
,validators
成员不是函数,并且一直null
在我的测试中)。编译后的 JS 说这个函数需要一个control
参数;我试过传入FormControl
引用,但据我所知,只要此参数不为空,它只会返回控件上的验证器。
Getting validators on a FormControl
在 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}
Making it easier to grab:
使抓取更容易:
public hasValidator(control: string, validator: string): boolean {
return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
// returns true if control has the validator
}
and in your markup:
并在您的标记中:
<md-input-container>
<input placeholder="Placeholder"
mdInput [formControl]="anyCtrl"
[required]="hasValidator('anyCtrl', 'email')">
</md-input-container>
Special case for Validators.required
Validators.required 的特殊情况
The required
validator has a shortcut. The [required]
binding is actually an instance of the RequiredValidator
directive(line 5022 of source/forms.js). This directive actually will add the required
Validator to the FormControl
it's on. It's equivalent to adding Validators.required
to the FormGroup
upon initialization. So, setting the bound property to false will remove the required
Validator from that control and vice versa...either way, the directive effects the FormControl.required
value, so binding it to a property that it changes won't really do much.
该required
验证器的快捷方式。的[required]
结合实际上是实例RequiredValidator
指令(源极/ forms.js的线5022)。该指令实际上会将required
验证器添加到FormControl
它所在的位置。这相当于增加了Validators.required
在FormGroup
初始化时。因此,将绑定属性设置为 falserequired
将从该控件中删除验证器,反之亦然......无论哪种方式,指令都会影响该FormControl.required
值,因此将其绑定到它更改的属性实际上不会做太多事情。
The only difference is that the [required]
directive adds the asterisk to the placeholder while Validators.required
does not.
唯一的区别是[required]
指令将星号添加到占位符,而Validators.required
没有。
I'm going to keep looking into NG_VALIDATORS
, but I hope this helps for now!
我会继续研究NG_VALIDATORS
,但我希望这对现在有所帮助!
回答by HankCa
This answer is a continuation of @joh04667's. They wrote:
这个答案是@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
}
However there is no AbstractControls.validators()
method. I'm assuming AbstractControls.validator()
was meant.
然而没有AbstractControls.validators()
方法。我假设AbstractControls.validator()
是这个意思。
The hasValidator()
method only works for validators that 'fail' (eg. a required validator on a control with the value '' (empty)). Since if they pass they return null. A way around this would be to set the value so that it always fails and restore that afterwards.
该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;
}
And this is pretty horrible. It begs the question - Why is there no AbstractControl.getValidators(): ValidatorFn[]|null
?
这是非常可怕的。这就引出了一个问题——为什么没有AbstractControl.getValidators(): ValidatorFn[]|null
?
What is the motivation in hiding this? Perhaps they are worried someone might put in their code:
隐藏这个的动机是什么?也许他们担心有人可能会放入他们的代码:
...
secretPassword: ['', [Validators.pattern('fjdfjafj734738&UERUEIOJDFDJj')]
...
回答by lunanigra
Based on mtinner's commend https://github.com/angular/angular/issues/13461#issuecomment-340368046we built our own directive to mark mandatory fields accordingly.
基于 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
) { }
}
The directive sets a 'required' attribute. This attribute can be addressed via CSS. The directive works on normal HTML input tags as well as on Angular Material form fields. To work with Angular Material we had to add a little workaround as the 'required' attribute has to be set on the enclosing form field tag; not only on the actual input field. Therefore the parent component is pass-through to the directive constructor.
该指令设置了“必需”属性。该属性可以通过 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>
回答by Erik van den Hoorn
I adjusted the code from joh04667 and HankCa to this:
我将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));
};
Which I store in a file called util.ts and import in the component that contains the form like this:
我将其存储在一个名为 util.ts 的文件中并导入包含如下表单的组件中:
import * as util from '@app/shared/util';
And define util in your class:
并在您的类中定义 util:
public util = util;
Add the directive to your input component like this:
将指令添加到您的输入组件中,如下所示:
[required]="util.hasValidator(myForm, 'path.to.control', 'required')"