• angular 自定义验证器


    先说"响应式表单"的用法

    新建的文件,用来写自定义验证器

    import { AbstractControl } from "@angular/forms";
    //control是我们要验证的表单控件, export
    function beginWith(control: AbstractControl) { const result = /^13/.test(control.value); return result ? null : {'beginWith': {value: control.value}};
    }

    上面返回语句中的"beginWith"是我们自定义的一个错误类型名,如果被验证的控件不满足我们自定义的这个验证规则, 控件元素的实例对象

    在组件类文件中

    //要引用自定义验证器的文件,并且引入表单相关类
    import { beginWith } from '....../上面定义验证器函数的文件名';
    import { FormGroup, FormControl, Validators } from '@angular/forms'; //Validators是ng自带的内置验证器类,里面有一些对html5验证规则的封装方法.

    ...

      //在constructor中定义表单控件实例,并用内置验证器和自定义验证器始初化
      this.heroForm = new FormGroup({     
          phone: new FormControl('蝙蝠侠', [Validators.required, Validators.minLength(4),beginWith])
      });
     
      //一定要加上这个getter属性,这样在模板中才能取到name,下面模板中name.errors中的name就是通过这个getter方法取到的
      get phone() { return this.heroForm.get('name'); }

    在模板中

    <form [formGroup]="heroForm" novalidate>
        <input id="phone" name="phone" formControlName="phone" autocomplete="off">        
        <div *ngIf="phone.invalid && (phone.dirty || phone.touched)" class="alert alert-danger">
            <div *ngIf="phone.errors.required">
                必填
            </div>
            <div *ngIf="phone.errors.minlength">
                至少4个字母
            </div>
            <div *ngIf="phone.errors.beginWith">
                必须是13
            </div>
        </div>
    </form>

    上面定义的验证器中的正则表达式是写死了, 可以改造一下,  (这也是官方文档的例子https://angular.cn/guide/form-validation#adding-to-reactive-forms):

    export function beginWith(regExp: RegExp): ValidatorFn {
      return (control: AbstractControl): {[key: string]: any} | null => {
        const isMatch = regExp.test(control.value);
        return isMatch ? null : {'beginWith': {value: control.value}};
      };
    }

     之前的写法其实就是直接export(导出)一个验证器函数(ValidatorFn),这个修改的写法就是个工厂函数,即调用它时要传进来一个正则表达式,它会返回一个使用这个正则表达式创建的验证器函数(ValidatorFn),ValidatorFn是一个函数接口,参数为一个表单控件对象,返回值是一个错误信息对象或null(如果没有错误).

    相应的组件类中的创建表单对象的代码也要改下:

    this.heroForm = new FormGroup({
        name: new FormControl('蜘蛛侠', [Validators.required, Validators.minLength(4), beginWith(/^13/)])
    });

     "响应式表单"的实现方式需要在表单组件类所在模块( 可能是根模块 )引入ReactiveFormsModule,

    import { FormsModule, ReactiveFormsModule } from '@angular/forms';

    接下来看下模板驱动表单的实现方式:

    用自定义指令的方式将上面写自定义验证器进行包装 : 官方的原文:必须创建一个指令,它会包装这个验证器函数。我们使用 NG_VALIDATORS 令牌来把它作为验证器提供出来. https://angular.cn/guide/form-validation#adding-to-reactive-forms

    // 自定义验证器
    import { ValidatorFn, AbstractControl, NG_VALIDATORS, Validator } from "@angular/forms";
    import { Directive, Input } from "@angular/core";
    
    export function beginWith(nameRe: RegExp): ValidatorFn {
      return (control: AbstractControl): { [key: string]: any } | null => {
        const result = nameRe.test(control.value);
        return result ? null : { 'beginWith': { value: control.value } };
      };
    }
    
    @Directive({
      selector: '[phone]', //在模板中的属性指令就要写成 phone="..."
      providers: [{
        provide: NG_VALIDATORS, //这里我还没太搞弄,参考下官方文档吧
        useExisting: ForbiddenValidatorDirective, //这个属性的意思官方文档上写的我也没太懂,总之呢要和下面类名一致
        multi: true //官方文档是说要想让一个控件同时支持多个验证器就要写 multi: true
      }]
    })
    export class ForbiddenValidatorDirective implements Validator {
      @Input('phone') regExp_str: string; //通过模板上的属性指令取到的字符串值
    
      validate(control: AbstractControl): { [key: string]: any } | null {
        const regExp = new RegExp(this.regExp_str, 'i'); //创建正则表达式对象
        const validatFn = beginWith(regExp);  //直接调用上面定义的工厂函数, 它返回的是一个验证器函数
        return this.regExp_str ? validatFn(control) : null; //然后调用这个验证器, control就是当前指令所属的表单控件
      }
    }

    修改组件类的代码:

    ...
    export class MyApp {
      ...
      //"模板驱动式表单"的数据就直接用类属性定义
      hero = {
        phone: '13333333333'
      };
    
      constructor() {
    //      this.heroForm = new FormGroup({
    //        name: new FormControl('王宁', [Validators.required, Validators.minLength(4), beginWith(/^123/)])
    //      });
      }
    
      //get name() { return this.heroForm.get('name'); }
    }

    然后 修改一下模板

    <form>
        <input id="phone" name="phone" required minlength="11" phone="^13" [(ngModel)]="hero.phone" #phone="ngModel" autocomplete="off">
    
        <div *ngIf="phone.invalid && (phone.dirty || phone.touched)" >
            <div *ngIf="phone.errors.required">
                必填
            </div>
            <div *ngIf="phone.errors.minlength">
                至少11位数
            </div>
            <div *ngIf="phone.errors.beginWith">
                手机号必须是13开头
            </div>
        </div>
    </form>

    "模板驱动式表单"中, 需要定义模板变量 #xxx="ngModel" (就是上面的#phone), 下面的错误提示DIV中用的phone.invalid 和 phone.dirty 等,其中的phone就是这个模板变量xxx,即指向被绑定的数据模型,这里是hero.phone

    喜欢的话,请点赞,转发、收藏、评论,谢谢!
  • 相关阅读:
    Android_EditText
    JAVA_Gson_example
    JAVA_Gson
    JAVA_eclipse 保留Java文件时自动格式化代码和优化Import
    JAVA_JSON_example
    JAVA_JSON
    JAVA_HttpClientUtils
    Android_Gallery
    JAVA_JDBC
    day05 Pyhton学习
  • 原文地址:https://www.cnblogs.com/johnjackson/p/11122030.html
Copyright © 2020-2023  润新知