如何根据 Angular 2 中的自定义验证规则显示错误消息?

     2023-02-22     72

关键词:

【中文标题】如何根据 Angular 2 中的自定义验证规则显示错误消息?【英文标题】:How to display error message based on custom validation rules in Angular 2? 【发布时间】:2016-11-28 17:59:35 【问题描述】:

我正在使用模板驱动的方法在 Angular 2 中构建表单,并且我已经成功创建了可以在模板中使用的自定义验证器。

但是,我找不到显示绑定到特定错误的特定错误消息的方法。我想区分为什么表格无效。我如何做到这一点?

        import  Component  from '@angular/core';

    import  NgForm  from '@angular/forms';

    import  Site  from './../site';

    import  BackendService  from './../backend.service';

    import  email  from './../validators';

    import  CustomValidators  from './../validators';

    @Component(
        templateUrl: 'app/templates/form.component.html',
        styleUrls: ['app/css/form.css'],
        directives: [CustomValidators.Email, CustomValidators.Url, CustomValidators.Goof],
        providers: [BackendService]
    )

    export class FormComponent 
        active = true;
        submitted = false;
        model = new Site();

        onSubmit() 
            this.submitted = true;
            console.log(this.model);
        

        resetForm() 
            this.model = new Site();
            this.submitted = false;
            this.active = false;
            setTimeout(() => this.active = true, 0);
        

        get diagnostics() 
            return JSON.stringify(this.model)
        
    

import  Directive, forwardRef  from '@angular/core';
import  NG_VALIDATORS, FormControl  from '@angular/forms';
import  BackendService  from './backend.service';

function validateEmailFactory(backend:BackendService) 
    return (c:FormControl) => 
        let EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`|~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;

        return EMAIL_REGEXP.test(c.value) ? null : 
            validateEmail: 
                valid: false
            
        ;
    ;


export module CustomValidators 

    @Directive(
        selector: '[email][ngModel],[email][formControl]',
        providers: [
            provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Email), multi: true
        ]
    )
    export class Email 
        validator:Function;

        constructor(backend:BackendService) 
            this.validator = validateEmailFactory(backend);
        

        validate(c:FormControl) 
            return this.validator(c);
        
    

    @Directive(
        selector: '[url][ngModel],[url][formControl]',
        providers: [
            provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Url), multi: true
        ]
    )
    export class Url 
        validator:Function;

        constructor(backend:BackendService) 
            this.validator = validateEmailFactory(backend);
        

        validate(c:FormControl) 
            var pattern = /(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]2,256\.[a-z]2,4\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/;

            return pattern.test(c.value) ? null : 
                validateEmail: 
                    valid: false
                
            ;
        
    

    @Directive(
        selector: '[goof][ngModel],[goof][formControl]',
        providers: [
            provide: NG_VALIDATORS, useExisting: forwardRef(() => CustomValidators.Goof), multi: true
        ]
    )
    export class Goof 
        validate(c:FormControl) 
            return 
                validateGoof: 
                    valid: false
                
            ;
        
    

【问题讨论】:

【参考方案1】:

您可以只检查AbstractControl#hasError(...) 方法来查看控件是否存在特定错误。 FormGroupFormControl 都是 AbstractControls。对于FormControl,您只需将错误名称作为参数传递。例如

function regexValidator(control: FormControl): [key:string]: boolean 
  if (!control.value.match(/^pee/)) 
    return  'badName': true ;
  


<div *ngIf="!nameCtrl.valid && nameCtrl.hasError('badName')"
     class="error">Name must start with <tt>pee</tt>.
</div>

验证器方法应该返回一个字符串/布尔映射,其中键是错误的名称。这是您在 hasError 方法中检查的名称。

对于FormGroup,您可以将FormControl 的路径作为额外参数传递。

<div *ngIf="!form.valid && form.hasError('required', ['name'])"
     class="error">Form name is required.</div>

name 只是输入的FormControl 的标识符。

这是一个同时使用FormControlFormGroup 检查的示例。

import  Component  from '@angular/core';
import 
  FormGroup,
  FormBuilder,
  FormControl,
  Validators,
  AbstractControl,
  REACTIVE_FORM_DIRECTIVES
 from '@angular/forms';

function regexValidator(control: FormControl): [key:string]: boolean 
  if (!control.value.match(/^pee/)) 
    return  'badName': true ;
  


@Component(
  selector: 'validation-errors-demo',
  template: `
    <div>
      <h2>Differentiate Validation Errors</h2>
      <h4>Type in "peeskillet"</h4>
      <form [formGroup]="form">
        <label for="name">Name: </label>
        <input type="text" [formControl]="nameCtrl"/>
        <div *ngIf="!nameCtrl.valid && nameCtrl.hasError('required')"
             class="error">Name is required.</div>
        <div *ngIf="!nameCtrl.valid && nameCtrl.hasError('badName')"
             class="error">Name must start with <tt>pee</tt>.</div>
        <div *ngIf="!form.valid && form.hasError('required', ['name'])"
             class="error">Form name is required.</div>
      </form>
    </div>
  `,
  styles: [`
    .error 
      border-radius: 3px;
      border: 1px solid #AB4F5B;
      color: #AB4F5B;
      background-color: #F7CBD1;
      margin: 5px;
      padding: 10px;
    
  `],
  directives: [REACTIVE_FORM_DIRECTIVES],
  providers: [FormBuilder]
)
export class ValidationErrorsDemoComponent 
  form: FormGroup;
  nameCtrl: AbstractControl;

  constructor(formBuilder: FormBuilder) 
    let name = new FormControl('', Validators.compose([
      Validators.required, regexValidator
    ]));
    this.form = formBuilder.group(
      name: name
    );
    this.nameCtrl = this.form.controls['name'];
  


更新

好的,我让它工作了,但它有点冗长。我不知道如何正确访问输入的个人FormControl。所以我所做的只是创建一个对FormGroup的引用

<form #f="ngForm" novalidate>

然后为了检查有效性,我只使用传递表单控件名称路径的hasError 重载。对于使用namengModel&lt;input&gt;name 值将添加到主FormGroup 中,该名称作为FormControl 名称。所以你可以像这样访问它

`f.form.hasError('require', ['nameCtrl'])`

假设name=nameCtrl。注意f.formfNgForm 实例,它有一个FormGroup 成员变量form

下面是重构示例

import  Component, Directive  from '@angular/core';
import 
  FormControl,
  Validators,
  AbstractControl,
  NG_VALIDATORS,
  REACTIVE_FORM_DIRECTIVES
 from '@angular/forms';

function validateRegex(control: FormControl): [key:string]: boolean 
  if (!control.value || !control.value.match(/^pee/)) 
    return  'badName': true ;
  

@Directive(
  selector: '[validateRegex]',
  providers: [
     provide: NG_VALIDATORS, useValue: validateRegex, multi: true 
  ]
)
export class RegexValidator 


@Component(
  moduleId: module.id,
  selector: 'validation-errors-template-demo',
  template: `
    <div>
      <h2>Differentiate Validation Errors</h2>
      <h4>Type in "peeskillet"</h4>
      <form #f="ngForm" novalidate>
        <label for="name">Name: </label>

        <input type="text" name="nameCtrl" ngModel validateRegex required />

        <div *ngIf="!f.form.valid && f.form.hasError('badName', ['nameCtrl'])"
             class="error">Name must start with <tt>pee</tt>.</div>

        <div *ngIf="!f.form.valid && f.form.hasError('required', ['nameCtrl'])"
             class="error">Name is required.</div>
      </form>
    </div>
  `,
  styles: [`
    .error 
      border-radius: 3px;
      border: 1px solid #AB4F5B;
      color: #AB4F5B;
      background-color: #F7CBD1;
      margin: 5px;
      padding: 10px;
    
  `],
  directives: [REACTIVE_FORM_DIRECTIVES, RegexValidator]
)
export class ValidationErrorsTemplateDemoComponent 


【讨论】:

这很有帮助,但是您正在使用模型驱动的方法来构建表单(使用 FormBuilder)。当我使用模板驱动时,我不知道如何在 html 中公开 AbstractControl 来询问它是否有错误。我总是得到 hasError is not a function 或类似的东西。 在您的模板中,这些模型被隐式创建以表示输入。您仍然可以从模板访问它们,而根本没有任何成员模型变量。您只需要在模板中创建引用变量。如果您发布更完整的示例,我可以尝试帮助您 例如,在您的表单中您可以使用&lt;form #f="ngForm"&gt;,现在f 是代表FormGroup 的变量。 ngForm 是提供的东西,所以你不必担心它来自哪里。同样对于您的不同输入,您可以使用&lt;input #nameInput [formControl]="nameInput"&gt;,并且nameInput 将作为FormControl 添加到f 表单中。有很多不同的方法来设置声明性模板。如果您需要更多帮助,我可能需要在您的模板中查看您的设置 我想要一个带有 1 个输入(以声明方式)的简单表单,它与模型双向绑定,并且我可以访问模板的 AbstractControl 表单以检查其有效性和自定义错误。 [formControl]="nameInput" 抛出 Can't bind to 'formControl' 因为它不是已知的本机属性 查看我的更新。我得到了它的工作,但不是我认为它应该工作的方式。看来我的假设是不正确的。【参考方案2】:

对于模板驱动的验证,使用如下属性指令:

import  Model  from '../../models';
import  Directive, Attribute, forwardRef, Input  from '@angular/core';
import  NG_VALIDATORS, Validator, AbstractControl  from '@angular/forms';

@Directive(
    selector: '[unique-in-list][formControlName],[unique-in-list][formControl],[unique-in-list][ngModel]',
    providers: [
         provide: NG_VALIDATORS, useExisting: forwardRef(() => UniqueInListDirectiveValidator), multi: true 
    ]
)
export class UniqueInListDirectiveValidator implements Validator 
     @Input('list') private list: Model[];
     @Input('property') private _property: string;
     @Input('thisid') private _myId: string;

     validate(control: AbstractControl):  [key: string]: any  

        let currValue = control.value;
        if (currValue && currValue.length > 0 && this.list && Array.isArray(this.list) && this.list.length > 0) 
            let model = this.list.find(
                (testModel: Model) => 
                    return testModel.modelId !== this._myId && testModel[this._property] === currValue;
                
            );
            if (model) 
                return  isUnique: true 
            
        
        return null;
    

.. 在您的模板中使用随附的标记:

<input
    type="text"
    #nameVar="ngModel"
    name="name"
    class="form-control name-field"
    unique-in-list
    [list]="models"
    [thisid]="model.modelId"
    property="name"
    [(ngModel)]="model.name"
    required
/>
<div *ngIf="nameVar.errors?.required && (submitted || !nameVar.pristine)" class="alert-classes-here">
    <div>Name is required</div>
</div>
<div *ngIf="nameVar.errors?.isUnique && (submitted || !nameVar.pristine)" class="alert-classes-here">
    <div>Name is already taken</div>
</div>

HTH

【讨论】:

【参考方案3】:

我从 AngularJs 编写了一组类似于 ng-messages 的指令来解决 Angular 中的这个问题。 https://github.com/DmitryEfimenko/ngx-messages

<div [val-messages]="myForm.get('email')">
  <span val-message="required">Please provide email address</span>
  <span val-message="server" useErrorValue="true"></span>
</div>

【讨论】:

angular 2+ 中的自定义输入类型

】angular2+中的自定义输入类型【英文标题】:Custominputtypesinangular2+【发布时间】:2018-06-1123:07:33【问题描述】:我想为我的Angular2项目使用自定义输入类型(即)&lt;inputtype=\'dob\'&gt;创建自定义验证。我在堆栈溢出中看到了... 查看详情

Angular4 中的自定义验证

】Angular4中的自定义验证【英文标题】:CustomvalidationinAngular4【发布时间】:2018-07-2918:52:21【问题描述】:在我的页面中,我有一个简单的表单组。我必须在其中为名称编写自定义验证。this.searchForm=this._formBuilder.group(profileName:newF... 查看详情

使用带有附加参数的自定义规则验证 Laravel 中的数组

】使用带有附加参数的自定义规则验证Laravel中的数组【英文标题】:ValidatingarrayinLaravelusingcustomrulewithadditionalparameter【发布时间】:2019-07-2414:42:24【问题描述】:我正在使用Laravel5.7,我需要使用2个输入(前缀+数字)来验证电话... 查看详情

Angular2 - 使用旧数据的自定义验证器

】Angular2-使用旧数据的自定义验证器【英文标题】:Angular2-Customvalidatorusingolddata【发布时间】:2017-06-2823:18:28【问题描述】:我编写的自定义验证器有问题。验证器用于验证组件中的所有数据。设置如下:组件显示一个包含X行... 查看详情

Angular 5 动态表单中的自定义验证器

】Angular5动态表单中的自定义验证器【英文标题】:CustomvalidatorinAngular5dynamicforms【发布时间】:2018-05-2810:54:18【问题描述】:我正在从Angular5中的可配置json创建一个动态表单。一切正常,但我无法为特定字段添加自定义验证器。... 查看详情

将预定义的验证器添加到 Angular 中的自定义组件

】将预定义的验证器添加到Angular中的自定义组件【英文标题】:AddpredefinedvalidatortoacustomcomponentinAngular【发布时间】:2017-10-1008:22:02【问题描述】:我正在开发一个自定义组件,用于Angular中的表单。我正在实现ControlValueAccessor接... 查看详情

jQuery 验证器和使用 AJAX 的自定义规则

...我阅读了您关于jQuery验证器的回复,您在其中概述了一种根据数据库中的值检查用户名的方法。我尝试过实现此方法,但无论从PHP文件返回什么,我总是会收到用户名已被占用的消息。这是自定义方法...$.validator.addMetho 查看详情

是否可以在没有 tfs 服务器的情况下验证 vs2010 中的自定义代码/架构规则?

...我们有TFS。我们很快就会迁移到TFS,但我想知道是否可以根据未附加到TFS的策略检查代码。特别是,如果您可以在根本 查看详情

验证不会传播到 Angular 中的自定义表单控件 ng-select

】验证不会传播到Angular中的自定义表单控件ng-select【英文标题】:ValidationisnotpropagatetoCustomFormControlng-selectinAngular【发布时间】:2020-06-1223:43:55【问题描述】:我在Angular9应用程序中使用带有自定义表单控件的反应式表单。我用... 查看详情

Angular - 模板驱动的表单 - 控制器中的自定义验证器功能

】Angular-模板驱动的表单-控制器中的自定义验证器功能【英文标题】:Angular-Templatedrivenforms-customvalidatorfunctioninthecontroller【发布时间】:2019-03-2306:30:29【问题描述】:由于在ngModel中使用响应式表单是deprecatedinAngular6,并且我的项... 查看详情

Angular 6. 如何在创建的自定义控件中赋予验证状态这个控件?

】Angular6.如何在创建的自定义控件中赋予验证状态这个控件?【英文标题】:Angular6.HowinthecreatedCustomControltogivenValidatorstatethiscontol?【发布时间】:2018-12-2509:51:48【问题描述】:我为表单创建了一个自定义控件。我的控件是这样的... 查看详情

Laravel Spark 中的自定义验证消息

...规则和自定义消息传递给验证功能,但不确定我在Spark中如何做。Spark::validateUsersWith(funct 查看详情

Angular 2 / Material - 应用到父 FormGroup 的自定义验证器未显示 md 错误

】Angular2/Material-应用到父FormGroup的自定义验证器未显示md错误【英文标题】:Angular2/Material-md-errornotdisplayedwithcustomvalidatorappliedtoparentFormGroup【发布时间】:2018-03-0200:01:12【问题描述】:我在使用Angular(v4.3.6)在模型驱动表单上显示... 查看详情

如何从 ASP.NET Core 2.0 中的自定义中间件请求身份验证

】如何从ASP.NETCore2.0中的自定义中间件请求身份验证【英文标题】:HowtorequestauthenticationfromcustommiddlewareinASP.NETCore2.0【发布时间】:2018-10-2118:41:09【问题描述】:我有两个自定义ASP.NETCore中间件:一个用于身份验证(注册自己的身... 查看详情

CORS Preflight 请求 - 标头中的自定义身份验证令牌 - Spring 和 Angular 4

】CORSPreflight请求-标头中的自定义身份验证令牌-Spring和Angular4【英文标题】:CORSPreflightrequest-Customauthtokeninheader-SpringandAngular4【发布时间】:2018-04-2323:07:42【问题描述】:我在本地服务器上使用令牌作为标头请求简单GET时遇到问... 查看详情

如何使唯一数组的自定义验证规则依赖于其他字段 laravel

】如何使唯一数组的自定义验证规则依赖于其他字段laravel【英文标题】:HowtomakeCustomValidationruleforuniqueArraydependentonotherfieldlaravel【发布时间】:2019-08-1203:53:19【问题描述】:我正在开发Laravel5.6。我有4个依赖的唯一列,但不知道... 查看详情

jQuery Validate Plugin - 如何创建一个简单的自定义规则?

】jQueryValidatePlugin-如何创建一个简单的自定义规则?【英文标题】:jQueryValidatePlugin-Howtocreateasimplecustomrule?【发布时间】:2010-09-1911:04:07【问题描述】:如何使用不使用正则表达式的jQueryValidate插件(使用addMethod)创建简单的自... 查看详情

如何将样式应用于 Angular 中的自定义组件内容?

】如何将样式应用于Angular中的自定义组件内容?【英文标题】:HowtoapplyStyletocustomcomponentcontentinAngular?【发布时间】:2019-11-0303:12:02【问题描述】:我正在尝试将样式应用于自定义组件的子组件。选择器:<custom-component-example>... 查看详情