|
先说"响应式表单"的用法
新建的文件,用来写自定义验证器
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
喜欢的话,请点赞,转发、收藏、评论,谢谢!
来源:https://www.cnblogs.com/johnjackson/p/11122030.html |