显示角度反应形式错误消息的最佳方法,一个表单控制多个验证错误?

Posted

技术标签:

【中文标题】显示角度反应形式错误消息的最佳方法,一个表单控制多个验证错误?【英文标题】:Best way to show error messages for angular reactive forms, one formcontrol multiple validation errors? 【发布时间】:2019-03-17 04:59:37 【问题描述】:

我正在按照 angular angular form validation error example 的建议方法显示反应形式的错误消息。

页面显示错误的html代码:

<div [formGroup]="myForm">
  <div>
<input type="text" formControlName="firstName"/>
<div *ngIf="myForm.controls.firstName.invalid"
    class="alert alert-danger">
    <div *ngIf="myForm.controls.firstName.errors.required">
      This Field is Required.
    </div>
    <div *ngIf="myForm.controls.firstName.errors.maxlength">
      your can enter only 50 characters
    </div>
</div>
  </div>
  <div>
<input type="text" formControlName="lastName"/>
<div *ngIf="myForm.controls.lastName.invalid"
    class="alert alert-danger">
    <div *ngIf="myForm.controls.lastName.errors.required">
      This Field is Required.
    </div>
    <div *ngIf="myForm.controls.lastName.errors.maxlength">
      your can enter only 50 characters
    </div>
</div>
  </div>
  </div>

仅供参考我的组件代码如下:

this.myForm = this.formBuilder.group(
      firstName:['',[Validators.required,Validators.maxLength(50)]],
      lastName:['',[Validators.required,Validators.maxLength(50)]]
    )

如果您看到上面的代码,我已经对我的名字和姓氏字段应用了两次验证。

为了显示错误信息,我写了多个 *ngIf 条件来显示错误信息。

有没有最好的方法来显示特定控件的验证消息而无需编写多个 *ngIf 条件?因为我一次又一次地使用不同的控件名称和验证器名称编写相同的代码来显示错误消息。

【问题讨论】:

您可以实现自己的验证器指令 每条错误消息都需要一个*ngIf。对于验证器,您可以实现一个返回不同值的验证器,您可以对其进行评估。 @VithuBati, HDJEMAI 如果您分享小代码示例或一些参考链接,那就太好了。 如果可能的话,我会尝试用你的最少代码创建一个例子,我可能需要一些时间来回答。 【参考方案1】:

我建议有一个名为 print-error 的组件,它可以处理任何类型的 OOTB 或自定义错误。

您可以处理任意数量的错误。

打印错误.component.ts

import Component, Input from '@angular/core';

@Component(
    selector: 'print-error',
    templateUrl: './print-error.component.html',
    providers: []
)
export class PrintError 

    @Input("control")
    control: any;


打印错误.component.html

<div class="text-danger" *ngIf="control && control.errors && (control.dirty || control.touched)">
     <div *ngIf="control.errors.required"><small>This field is required</small></div>
     <div *ngIf="control.errors.unique"><small>control.errors.unique</small></div>
     <div *ngIf="control.errors.lessThen"><small>control.errors.lessThen</small></div>
     <div *ngIf="control.errors.greaterThan"><small>control.errors.greaterThan</small></div>
     <div *ngIf="control.errors.email"><small>control.errors.email</small></div>
     <div *ngIf="control.errors.mobile"><small>control.errors.mobile</small></div>
     <div *ngIf="control.errors.confirmPassword"><small>control.errors.confirmPassword</small></div>
</div>

用法

 <label for="folder-name">Email</label>
 <input name="email" required   emailValidator #email="ngModel" [(ngModel)]="user.email">
 <print-error [control]="email"></print-error>

【讨论】:

喜欢这个想法,但我收到以下错误:( 错误错误:没有未指定名称属性的表单控件的值访问器 您应该使用name 属性进行控制。参考***.com/questions/46708080/… 这是一个不错的方法,那么如何在打印错误组件中获取无效控件的名称?【参考方案2】:

处理所有错误的更好方法,创建一个单独的组件error-component

error.component.ts

import  Component, Input  from '@angular/core';
import  AbstractControl, AbstractControlDirective  from '@angular/forms';

@Component(
    selector: 'error-component',
    templateUrl: 'error.component.html',
    styleUrls: ['error.component.scss']
)

export class ErrorComponent 

    errorMsgList: any = [];

    @Input() controlName: AbstractControl | AbstractControlDirective

    errorMessage = 
        'required'  : (params)  => `This field is required`,
        'maxlength' : (params)  => `Maximum $params.requiredLength characters are allowed`,
        'minlength' : (params)  => `Minimum $params.requiredLength characters are required`,
        'pattern'   : (params)  => `Invalid format`,
        'min'       : (params)  => `Minimum amount should be ₹ $params.min`,
        'whitespace': (params)   => `White spaces are not allowed`
    ;


    listErrors() 
        if (!this.controlName) return [];
        if (this.controlName.errors) 
            this.errorMsgList = [];
            Object.keys(this.controlName.errors).map( error => 
                this.controlName.touched || this.controlName.dirty ?
                this.errorMsgList.push(this.errorMessage[error](this.controlName.errors[error])) : '';
            );
            return this.errorMsgList;
        
        else 
            return [];
        
    

error.component.html

<small class="error-block" *ngFor="let errorMessage of listErrors(); let last=last;">
    last ? errorMessage: ''
</small>  

用法

<input 
   [type] ="inputObj.mobileNumber.type" 
   id="id1" name="custMobNumber" 
   [(ngModel)]="inputObj.mobileNumber.value" 
   [required]="inputObj.mobileNumber.required" 
   [minlength]="inputObj.mobileNumber.minLength" 
   [maxlength]="inputObj.mobileNumber.maxLength" 
   [pattern]="inputObj.mobileNumber.pattern" 
   class="textbox font-15 full-width">
   <error-component [controlName]="collectionForm.controls['custMobNumber']">
    </error-component>

【讨论】:

【参考方案3】:

我一直在开发一个主要形式驱动的企业应用程序,并且遇到了同样的挑战。我能确定的最佳解决方案是将所有输入控件包装在组件中。然后处理组件内的验证显示。这允许一致的验证显示,而无需在每个表单中多次重复代码。

field-input-text.component.html

    <input [formControl]="formControlItem" [maxlength]="maxlength" [placeholder]="placeholder" #input>
    <span *ngIf="formControlItem.invalid && (formControlItem.dirty || formControlItem.touched)" class="text-danger">
        <span *ngIf="formControlItem.errors.required">This field is required</span>
        <span *ngIf="formControlItem.errors.minlength">This field is too short</span>
        <span *ngIf="formControlItem.errors.maxlength">This field is too long</span>
        <span *ngIf="formControlItem.errors.pattern">Invalid value for this field</span>
    </span>

field-input-text-component.ts

    import  Component, OnInit  from '@angular/core';
    import  FormControl  from '@angular/forms';

    @Component(
      selector: 'app-field-input-text',
      templateUrl: './field-input-text.component.html'
    )
    export class FieldInputTextComponent implements OnInit, AfterViewInit 
      @Input() formControlItem: FormControl;
      @Input() maxlength: number;
      @Input() placeholder: string = '';

      constructor()  

      ngOnInit() 
      
    

用法

    <app-field-input-text [formControlItem]="form.controls.username" maxlength="10"></app-field-input-text>

在使用中,你可以看到它节省的空间,而不需要额外的验证行。您还可以在一个地方重新格式化所有验证,而不是触及每个区域。

主要缺点是不能使用 formControl 或 formControlName 属性。我尝试创建一个自定义 ControlValueAccessor 组件,但这对验证显示没有帮助。

我发现您的问题是在寻找其他人是否找到了更好的方法。我知道这个答案有点晚了,但希望对您有所帮助。

【讨论】:

【参考方案4】:

如果是小表格,我通常只使用大量*ngIf;但是,如果您的应用程序几乎完全是需要验证的表单,那么上面提到的自定义验证器指令可能会很有用。

查看源代码,了解如何设置内置验证器。 https://github.com/angular/angular/blob/2.0.0-rc.3/modules/%40angular/common/src/forms-deprecated/directives/validators.ts#L104-L124

这是我挖掘的一个示例,但我认为对于大多数用例来说这有点矫枉过正。只需在模板 HTML 中写一个 *ngIf 行,而不是一个全新的 @Attribute...

https://scotch.io/tutorials/how-to-implement-a-custom-validator-directive-confirm-password-in-angular-2

【讨论】:

有很多字段,我对此更感兴趣,它提供了没有 *ngIf,我可以显示多个角度验证器错误消息。 即使使用验证器,您也必须使用 *ngIf 或 CSS 类来显示您选择的任何错误消息。您可以根据需要显示尽可能多或尽可能少的内容。关于该主题的文档非常完整:angular.io/guide/form-validation【参考方案5】:

也许试试这个很棒的包:https://www.npmjs.com/package/ngx-form-validations

这个包有一个通用的错误信息字典,取决于错误类型。 它的安装一点也不复杂。

它可以管理您的整个表单,而不仅仅是一个控件。如果您需要一些额外的扩展,请随时在 GitHub 上与我联系。

此外:还有一个演示页面,您可以在其中轻松检查其操作,并且还有一个演示项目。联系方式可在包装中找到。

【讨论】:

以上是关于显示角度反应形式错误消息的最佳方法,一个表单控制多个验证错误?的主要内容,如果未能解决你的问题,请参考以下文章

formGroupDirective 用于重置表单 - Angular 反应式表单

角度材料 - mat-error 不显示输入字段的错误消息

无法以角度反应形式添加验证器

以反应形式设置图像 url 在角度 2 中给出错误

角度测试以反应形式提交事件

表单组件应具有哪个输出类型的角度2?