如何在 Angular(v2 及更高版本)反应形式中查找无效控件
Posted
技术标签:
【中文标题】如何在 Angular(v2 及更高版本)反应形式中查找无效控件【英文标题】:How to find the invalid controls in Angular(v2 onwards) reactive form 【发布时间】:2017-12-26 11:13:00 【问题描述】:我在 Angular 中有一个反应形式,如下所示:
this.AddCustomerForm = this.formBuilder.group(
Firstname: ['', Validators.required],
Lastname: ['', Validators.required],
Email: ['', Validators.required, Validators.pattern(this.EMAIL_REGEX)],
Picture: [''],
Username: ['', Validators.required],
Password: ['', Validators.required],
Address: ['', Validators.required],
Postcode: ['', Validators.required],
City: ['', Validators.required],
Country: ['', Validators.required]
);
createCustomer(currentCustomer: Customer)
if (!this.AddCustomerForm.valid)
//some app logic
this.AddCustomerForm.valid 返回 false,但一切看起来都不错。
我试图通过检查控件集合中的状态属性来查找。但是我想知道是否有办法找到无效的并显示给用户?
【问题讨论】:
如果你只想显示有错误的字段,你可以使用css来高亮或着色无效的字段。每个无效字段在其类列表中附加一个“ng-invalid”类 这是 Angular 中的一个未解决问题。您可以在此处竖起大拇指以提高优先级:github.com/angular/angular/issues/10530 当formGroup.errors 给出null
而formGroup.valid 给出false 时,可能是因为maxlength
等html 标签,它们不应该混合使用
【参考方案1】:
您可以简单地遍历每个控件并检查状态:
public findInvalidControls()
const invalid = [];
const controls = this.AddCustomerForm.controls;
for (const name in controls)
if (controls[name].invalid)
invalid.push(name);
return invalid;
【讨论】:
谢谢你,但我试过了,即使这个没有返回,我的表单仍然无效,这很奇怪。我的意思是这段代码看起来不错,但是为什么 form.valid 返回 false 没有任何意义findInvalidControls()
给你什么回报?
什么都不返回,invalid 为空。我在调试监视屏幕中一一检查,所有控件都有效但this.AddCustomerForm.valid仍然返回false。
@AngularInDepth.com - 如果其中一个控件是表单组,您的函数将返回无效的表单组,而不是无效的特定表单控件
我遇到了同样的问题,我的表单无效,但所有字段都有效。我通过field.setValue('1234', onlySelf: true)
更新了该字段。一旦我删除 onlySelf:true 它就会按预期工作!【参考方案2】:
我刚刚解决了这个问题:每个表单字段都有效,但表单本身仍然无效。
原来我在 FormArray 上设置了“Validator.required”,其中控件是动态添加/删除的。因此,即使 FormArray 为空,它仍然是必需的,因此表单始终无效,即使每个可见控件都已正确填充。
我没有找到表单的无效部分,因为我的“findInvalidControls”函数只检查了 FormControl 而不是 FormGroup/FormArray。所以我更新了一下:
/*
Returns an array of invalid control/group names, or a zero-length array if
no invalid controls/groups where found
*/
public findInvalidControlsRecursive(formToInvestigate:FormGroup|FormArray):string[]
var invalidControls:string[] = [];
let recursiveFunc = (form:FormGroup|FormArray) =>
Object.keys(form.controls).forEach(field =>
const control = form.get(field);
if (control.invalid) invalidControls.push(field);
if (control instanceof FormGroup)
recursiveFunc(control);
else if (control instanceof FormArray)
recursiveFunc(control);
);
recursiveFunc(formToInvestigate);
return invalidControls;
【讨论】:
哇哦。非常感谢,这为我节省了大量的调查时间!【参考方案3】:一个无效的 Angular 控件具有名为 'ng-invalid' 的 CSS 类。
在 Chrome 的 DevTools 下,选择控制台选项卡。
在控制台提示符下运行以下命令以获取带有 CSS 类“ng-invalid”的无效 Angular 控件
document.getElementsByClassName('ng-invalid')
输出应该与此类似:
在这种情况下,带下划线的文本用于表单控件listen-address
,而圈起来的文本:.ng-invalid
表示该控件无效。
注意:在 chrome 中测试
【讨论】:
【参考方案4】:现在,在 Angular 9 中,您可以使用 markAllAsTouched() 方法来显示无效控件验证器:
this.AddCustomerForm.markAllAsTouched();
【讨论】:
【参考方案5】:下面的代码将记录所有无效的控件?
for (let el in this.ReactiveForm.controls)
if (this.ReactiveForm.controls[el].errors)
console.log(el)
您可以从中创建一个数组或字符串并显示给用户
【讨论】:
【参考方案6】:表单和所有控件都扩展了 angular 类 AbstractControl。每个实现都有一个验证错误的访问器。
let errors = this.AddCustomerForm.errors
// errors is an instance of ValidatorErrors
api 文档包含所有参考 https://angular.io/api/forms/AbstractControl
编辑
我认为错误访问器是这样工作的,但是这个到 github 的链接表明还有一些其他人的想法和我一样 https://github.com/angular/angular/issues/11530
无论如何,通过使用控件访问器,您可以遍历表单中的所有 formControl。
Object.keys(this.AddCustomerForm.controls)
.forEach( control =>
//check each control here
// if the child is a formGroup or a formArray
// you may cast it and check it's subcontrols too
)
【讨论】:
即使有空控件也会返回 null 没有错误时应该返回null。你能发布你的模板吗? 是的,这行不通,在每个表单控件上设置了不同的验证,每个表单控件都包含错误,而表单没有。您需要像 Maximus 给出的答案那样迭代控件。 我可以访问每个单独控件的错误,例如 this.form.controls['Email'].errors @AJT_82 实际上,如果为 formGroup 设置了验证器,则表单本身可能会显示错误(检查有关跨字段验证的文档,这对在组上而不是在控件中进行验证是有意义的) 【参考方案7】:如果表单中没有太多字段,您可以简单地 F12 并将鼠标悬停在控件上,您将能够看到带有字段原始/已触摸/有效值的弹出窗口- “#fieldname.form-control.ng-untouched.ng-invalid”。
【讨论】:
【参考方案8】:我冒昧地改进了 AngularInDepth.com-s 的代码,以便它也递归地搜索嵌套形式的无效输入。它是由 FormArray-s 还是 FormGroup-s 嵌套的。只需输入顶层formGroup,它将返回所有无效的FormControl。
如果您将 FormControl 检查和添加到无效数组的功能分离到一个单独的函数中,您可能会略过一些“instanceof”类型检查。这将使函数看起来更简洁,但我需要一个全局的、单一的函数选项来获取所有无效 formControls 的平面数组,这就是解决方案!
findInvalidControls( _input: AbstractControl, _invalidControls: AbstractControl[] ): AbstractControl[]
if ( ! _invalidControls ) _invalidControls = [];
if ( _input instanceof FormControl )
if ( _input.invalid ) _invalidControls.push( _input );
return _invalidControls;
if ( ! (_input instanceof FormArray) && ! (_input instanceof FormGroup) ) return _invalidControls;
const controls = _input.controls;
for (const name in controls)
let control = controls[name];
switch( control.constructor.name )
case 'AbstractControl':
case 'FormControl':
if (control.invalid) _invalidControls.push( control );
break;
case 'FormArray':
(<FormArray> control ).controls.forEach( _control => _invalidControls = findInvalidControls( _control, _invalidControls ) );
break;
case 'FormGroup':
_invalidControls = findInvalidControls( control, _invalidControls );
break;
return _invalidControls;
只为那些需要它的人,所以他们不必自己编码..
编辑#1
要求它也返回无效的 FormArray-s 和 FormGroups,所以如果您也需要,请使用此代码
findInvalidControls( _input: AbstractControl, _invalidControls: AbstractControl[] ): AbstractControl[]
if ( ! _invalidControls ) _invalidControls = [];
if ( _input instanceof FormControl )
if ( _input.invalid ) _invalidControls.push( _input );
return _invalidControls;
if ( ! (_input instanceof FormArray) && ! (_input instanceof FormGroup) ) return _invalidControls;
const controls = _input.controls;
for (const name in controls)
let control = controls[name];
if (control.invalid) _invalidControls.push( control );
switch( control.constructor.name )
case 'FormArray':
(<FormArray> control ).controls.forEach( _control => _invalidControls = findInvalidControls( _control, _invalidControls ) );
break;
case 'FormGroup':
_invalidControls = findInvalidControls( control, _invalidControls );
break;
return _invalidControls;
【讨论】:
我试过了,但没有找到任何无效的 FormGroup 或 FormArray... 只有无效的 FormControl。我犯了同样的错误……看我的回答。 我改进了我的答案,以适应您的用例。【参考方案9】:您可以记录表单console.log(this.addCustomerForm.value)
的值,它将控制所有控件的值,然后 null 或“”(空)字段表示无效控件
【讨论】:
【参考方案10】:我认为您应该尝试使用this.form.updateValueAndValidity()
或尝试在每个控件中执行相同的方法。
【讨论】:
【参考方案11】:试试这个
findInvalidControls(f: FormGroup)
const invalid = [];
const controls = f.controls;
for (const name in controls)
if (controls[name].invalid)
invalid.push(name);
return invalid;
【讨论】:
【参考方案12】:就我而言,我禁用了所有表单控件。
这似乎是 Angular 中的一个开放错误:https://github.com/angular/angular/issues/39287
【讨论】:
您的情况,您能否解释一下这是否解决了问题,或者您禁用了表单控件是问题本身。责怪英语是解释性的.. :) 我的问题是表单看起来无效,但是当我试图找到一个无效的表单控件时,它们都不是。 “修复”是将某些字段设置为未禁用,但我不知道它是否适用于每个用例。【参考方案13】:所以我也反击了这条龙。 和我一样勇敢的骑士,我先聚集my weapons,阅读the maps,然后与这只可怕的野兽战斗。
注意
对于复杂的形式或结构来说,这不是一个可接受的答案,但我发现它适用于没有太多复杂性的简单形式
代码执行以下操作:
以数组形式获取表单控件 循环检查表单控件是否无效 如果无效,过滤器将包含它 如果任何一个无效,结果数组将填充该控件 如果这个结果的长度等于 0,我们可以声明没有控件是无效的并且整个表单都是有效的isFormValid = () :boolean =>
Object.values(this.form.controls)
.filter(c => c.invalid).length === 0
// or single lined
isFormValid = () :boolean => Object.values(this.form.controls).filter(c => c.invalid).length === 0
您可以在您想要的地方、提交按钮、onSubmit 或您自己的最佳位置使用它。
【讨论】:
【参考方案14】:解决上述问题的更简洁且不可变的递归版本:
P.S:这两种方法你都需要。
Angular 11 之前的工作测试
如果编译器抱怨flatMap,请参考this(Typescript flatMap, flat, flatten doesn't exist on type any[]),不要伪造重启
ng serve
findInvalidControls(controls = this.defaultFormGroup.controls)
const ctrls = Object.values(controls);
const names = Object.keys(controls);
return ctrls.map((a,i) => [a, i])
.filter(a => (a[0] as FormControl).invalid)
.flatMap(a =>
if (a[0] instanceof FormArray)
return this.findInvalidArrayControls(a[0].controls);
else if (a[0] instanceof FormGroup)
return this.findInvalidControls(a[0].controls);
else
return names[a[1] as number];
);
findInvalidArrayControls(controls: AbstractControl[])
const ctrls = Object.values(controls);
const names = Object.keys(controls);
return ctrls.map((a,i) => [a, i])
.filter(a => (a[0] as FormControl).invalid)
.flatMap(a =>
if (a[0] instanceof FormArray)
return this.findInvalidArrayControls(a[0].controls);
else if (a[0] instanceof FormGroup)
return this.findInvalidControls(a[0].controls);
else
return names[a[1] as number];
);
【讨论】:
【参考方案15】:检查html页面中的空或空表单控件值
表单控件值:formname.value | json【讨论】:
以上是关于如何在 Angular(v2 及更高版本)反应形式中查找无效控件的主要内容,如果未能解决你的问题,请参考以下文章
错误:Angular CLI v10.1.0 及更高版本(并且没有 `tsconfig.base.json`)
如何在Safari 10.1.2及更高版本中使用Dexie.js(v 2.0.1)数据库?
如何在 android 2.3 及更高版本中获取当前启动器的包名?