Angular 表单验证
模板驱动验证
使用模板驱动验证需要依赖于原生的HTML表单验证器 Angular 会用指令来匹配具有验证功能的这些属性。
原生的HTMl验证器主要分两种
- 通过语义类型来进行定义
- 通过验证相关的属性来进行定义
语义类型
Input type Constraint description Associated violation <input type="URL">
The value must be an absolute URL, as defined in the URL Living Standard. TypeMismatch constraint violation <input type="email">
The value must be a syntactically valid email address, which generally has the format username@hostname.tld
.TypeMismatch constraint violation
验证相关属性
Attribute Input types supporting the attribute Possible values Constraint description Associated violation pattern
text
,search
,url
,tel
,password
A JavaScript regular expression (compiled with the ECMAScript 5 global
,ignoreCase
, andmultiline
flags disabled)The value must match the pattern. patternMismatch
constraint violationmin
range
,number
A valid number The value must be greater than or equal to the value. rangeUnderflow
constraint violationdate
,month
,week
A valid date datetime
,datetime-local
,time
A valid date and time max
range
,number
A valid number The value must be less than or equal to the value rangeOverflow
constraint violationdate
,month
,week
A valid date datetime
,datetime-local
,time
A valid date and time required
text
,search
,url
,tel
,password
,date
,datetime
,datetime-local
,month
,week
,time
,number
,checkbox
,radio
,file
; also on the<select>
and<textarea>
elementsnone as it is a Boolean attribute: its presence means true, its absence means false There must be a value (if set). valueMissing
constraint violationstep
date
An integer number of days Unless the step is set to the any
literal, the value must be min + an integral multiple of the step.stepMismatch
constraint violationmonth
An integer number of months week
An integer number of weeks datetime
,datetime-local
,time
An integer number of seconds range
,number
An integer minlength
text
,search
,url
,tel
,password
; also on the<textarea>
elementAn integer length The number of characters (code points) must not be less than the value of the attribute, if non-empty. All newlines are normalized to a single character (as opposed to CRLF pairs) for <textarea>
.tooShort
constraint violationmaxlength
text
,search
,url
,tel
,password
; also on the<textarea>
elementAn integer length The number of characters (code points) must not exceed the value of the attribute. tooLong
constraint violation
每当表单控件中的值发生变化时,Angular就会进行验证,并生成一个验证错误的列表(对应着INVALID状态)或者null(对应着VALID状态);
可以通过吧ngModel导出成局部模板变量来查看控件的状态,比如像下面这样
<input id="name" name="name" class="form-control" required minlength="4" appForbiddenName="bob"[(ngModel)]="hero.name" #name="ngModel" ><div *ngIf="name.invalid && (name.dirty || name.touched)"class="alert alert-danger"><div *ngIf="name.errors.required">Name is required.</div><div *ngIf="name.errors.minlength">Name must be at least 4 characters long.</div><div *ngIf="name.errors.forbiddenName">Name cannot be Bob.</div>
</div>
#name="ngModel"
把 NgModel
导出成了一个名叫 name
的局部变量。NgModel
把自己控制的 FormControl
实例的属性映射出去,让你能在模板中检查控件的状态,比如 valid
和 dirty
。要了解完整的控件属性,参见 API 参考手册中的AbstractControl。
响应式表单的验证
响应式表单控制的源头在组件类,就不能通过模板上的属性来添加验证器了,而是直接在组件类中直接把验证器函数添加到表单控件模型(FormControl)上。当控件发生变化的时候就会调用这些函数。
ngOnInit(): void {this.heroForm = new FormGroup({'name': new FormControl(this.hero.name, [Validators.required,Validators.minLength(4),forbiddenNameValidator(/bob/i) // <-- Here's how you pass in the custom validator.]),'alterEgo': new FormControl(this.hero.alterEgo),'power': new FormControl(this.hero.power, Validators.required)});}
<input id="name" class="form-control" formControlName="name" required ><div *ngIf="name.invalid && (name.dirty || name.touched)"class="alert alert-danger"><div *ngIf="name.errors.required">Name is required.</div><div *ngIf="name.errors.minlength">Name must be at least 4 characters long.</div><div *ngIf="name.errors.forbiddenName">Name cannot be Bob.</div>
</div>
- 该表单不再导出任何指令,而是使用组件类中定义的
name
读取器。 required
属性仍然存在,虽然验证不再需要它,但你仍然要在模板中保留它,以支持 CSS 样式或可访问性。
从验证过程上看有两种验证器函数:同步验证器和异步验证器。
- 同步验证器函数接受一个控件实例,然后返回一组验证错误或null,可以在实例化FormControl的时候把函数作为构造函数的第二个参数传递进去。
- 异步验证器函数同样也接收一个控件实例,并返回一个承诺(Promise)或可观察对象(Observable),最终函数会返回一组验证错误或者null,可以在实例化FormControl的时候把她当做构造函数的第三个函数传递进去。
出于性能方面的考虑,只有在所有同步验证器都通过之后,Angular 才会运行异步验证器。当每一个异步验证器都执行完之后,才会设置这些验证错误。
从验证器来源来看也有两种验证器:内置验证器和自定义验证器
- 内置验证器与表单中使用的验证器类似,Validators都对应实现了其同名函数,具体如下 详见API
class Validators {static min(min: number): ValidatorFnstatic max(max: number): ValidatorFnstatic required(control: AbstractControl): ValidationErrors | nullstatic requiredTrue(control: AbstractControl): ValidationErrors | nullstatic email(control: AbstractControl): ValidationErrors | nullstatic minLength(minLength: number): ValidatorFnstatic maxLength(maxLength: number): ValidatorFnstatic pattern(pattern: string | RegExp): ValidatorFnstatic nullValidator(control: AbstractControl): ValidationErrors | nullstatic compose(validators: ValidatorFn[]): ValidatorFn | nullstatic composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn | null
}
- 自定义验证器:DEMO 如下,写在一起就能达到即给模板使用又给组件类使用的目的。
// 声明成指令给模板验证用 shared/forbidden-name.directive.ts (directive)
@Directive({selector: '[appForbiddenName]',providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}]
})
export class ForbiddenValidatorDirective implements Validator {@Input('appForbiddenName') forbiddenName: string;validate(control: AbstractControl): {[key: string]: any} | null {return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control) : null;}
}
// 定义函数给验证方法用
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {return (control: AbstractControl): {[key: string]: any} | null => {const forbidden = nameRe.test(control.value);return forbidden ? {'forbiddenName': {value: control.value}} : null;};
}
这个函数实际上是一个工厂,它接受一个用来检测指定名字是否已被禁用的正则表达式,并返回一个验证器函数。
forbiddenNameValidator
工厂函数返回配置好的验证器函数。 该函数接受一个 Angular 控制器对象,并在控制器值有效时返回 null,或无效时返回验证错误对象。 验证错误对象通常有一个名为验证秘钥(forbiddenName
)的属性。其值为一个任意词典,你可以用来插入错误信息({name}
)。
自定义异步验证器和同步验证器很像,只是它们必须返回一个稍后会输出 null 或“验证错误对象”的承诺(Promise)或可观察对象,如果是可观察对象,那么它必须在某个时间点被完成(complete),那时候这个表单就会使用它输出的最后一个值作为验证结果。(译注:HTTP 服务是自动完成的,但是某些自定义的可观察对象可能需要手动调用 complete 方法)
表示控件状态的CSS类
Angular 会自动把很多控件属性作为 CSS 类映射到控件所在的元素上。你可以使用这些类来根据表单状态给表单控件元素添加样式。目前支持下列类:
|
.ng-valid[required], .ng-valid.required { .ng-invalid:not(form) { |
跨字段交叉验证
除了单独的控件验证之外,有时候还需要多控件的联合验证,这个时候就需要用到跨字段的交叉验证方式。先粘代码
- 这个身份验证器实现了
ValidatorFn
接口。它接收一个 Angular 表单控件对象作为参数,当表单有效时,它返回一个 null,否则返回ValidationErrors
对象。 - 我们先通过调用
FormGroup
的 get 方法来获取子控件。然后,简单地比较一下name
和alterEgo
控件的值。
// 先定义指令给模板验证使用,指令调用导出的验证方法
@Directive({selector: '[appIdentityRevealed]',providers: [{ provide: NG_VALIDATORS, useExisting: IdentityRevealedValidatorDirective, multi: true }]
})
export class IdentityRevealedValidatorDirective implements Validator {validate(control: AbstractControl): ValidationErrors {return identityRevealedValidator(control)}
}
// 下面的方法给指令使用也可以给组件类使用
export const identityRevealedValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {const name = control.get('name');const alterEgo = control.get('alterEgo');return name && alterEgo && name.value === alterEgo.value ? { 'identityRevealed': true } : null;
};
响应式表单验证:需要在创建FormGroup时把一个新的验证器传给他的第二个参数.
const heroForm = new FormGroup({'name': new FormControl(),'alterEgo': new FormControl(),'power': new FormControl()
}, { validators: identityRevealedValidator });
模板驱动表单验证:我们要把该指令添加到 HTML 模板中。由于验证器必须注册在表单的最高层,所以我们要把该指令放在 form
标签上。
<form #heroForm="ngForm" appIdentityRevealed><!-- 错误输出-->
<div *ngIf="heroForm.errors?.identityRevealed && (heroForm.touched || heroForm.dirty)"
class="cross-validation-error-message alert alert-danger">Name cannot match alter ego.
</div>
异步验证器
就像同步验证器有 ValidatorFn
和 Validator
接口一样,异步验证器也有自己对应的接口:AsyncValidatorFn
和 AsyncValidator
。
它们非常像,但是有下列不同:
它们必须返回承诺(Promise)或可观察对象(Observable),
返回的可观察对象必须是有限的,也就是说,它必须在某个时间点结束(complete)。要把无尽的可观察对象转换成有限的,可以使用
first
、last
、take
或takeUntil
等过滤型管道对其进行处理。
注意!异步验证总是会在同步验证之后执行,并且只有当同步验证成功了之后才会执行。如果更基本的验证方法已经失败了,那么这能让表单避免进行可能会很昂贵的异步验证过程,比如 HTTP 请求。
在异步验证器开始之后,表单控件会进入 pending
状态。你可以监视该控件的 pending
属性,利用它来给用户一些视觉反馈,表明正在进行验证。
常见的 UI 处理模式是在执行异步验证时显示一个旋转指示标(spinner)。下面的例子展示了在模板驱动表单中该怎么做:
<input [(ngModel)]="name" #model="ngModel" appSomeAsyncValidator>
<app-spinner *ngIf="model.pending"></app-spinner>
实现自定义验证器
@Injectable({ providedIn: 'root' })
export class UniqueAlterEgoValidator implements AsyncValidator {constructor(private heroesService: HeroesService) {}validate(ctrl: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {return this.heroesService.isAlterEgoTaken(ctrl.value).pipe(map(isTaken => (isTaken ? { uniqueAlterEgo: true } : null)),catchError(() => of(null)));}
}
// HeroesService 负责向英雄数据库发起一个 HTTP 请求
interface HeroesService {isAlterEgoTaken: (alterEgo: string) => Observable<boolean>;
}
当验证开始的时候,UniqueAlterEgoValidator
把任务委托给 HeroesService
的 isAlterEgoTaken()
方法,并传入当前控件的值。这时候,该控件会被标记为 pending
状态,直到 validate()
方法所返回的可观察对象完成(complete)了。
isAlterEgoTaken()
方法会发出一个 HTTP 请求,并返回一个 Observable<boolean>
型结果。我们通过 map
操作符把响应对象串起来,并把它转换成一个有效性结果。 与往常一样,如果表单有效则返回 null
,否则返回 ValidationErrors
。我们还是用 catchError
操作符来确保对任何潜在错误都进行了处理。
这里,我们决定将 isAlterEgoTaken()
中的错误视为成功验证。你也可以将其视为失败,并返回 ValidationError
对象。
一段时间之后,可观察对象完成了,异步验证也就结束了。这时候 pending
标志就改成了 false
,并且表单的有效性也更新了。
性能上的注意事项
默认情况下,每当表单值变化之后,都会执行所有验证器。对于同步验证器,没有什么会显著影响应用性能的地方。不过,异步验证器通常会执行某种 HTTP 请求来对控件进行验证。如果在每次按键之后都发出 HTTP 请求会给后端 API 带来沉重的负担,应该尽量避免。
我们可以把 updateOn
属性从 change
(默认值)改成 submit
或 blur
来推迟表单验证的更新时机。
对于模板驱动表单:
<input [(ngModel)]="name" [ngModelOptions]="{updateOn: 'blur'}">
对于响应式表单:
new FormControl('', {updateOn: 'blur'});
Angular 表单验证相关推荐
- Angular 表单验证类库 ngx-validator 1.0 正式发布
背景介绍 之前写了一篇 <如何优雅的使用 Angular 表单验证>,结尾处介绍了统一验证反馈的类库 ngx-validator ,由于这段时间一直在新模块做微前端以及相关业务组件库,工具 ...
- 如何优雅的使用 Angular 表单验证
随便说说,这一节可以跳过 去年参加 ngChine 2018 杭州开发者大会的时候记得有人问我: Worktile 是什么时候开始使用 Angular 的,我说是今年(2018年) 3 月份开始在新模 ...
- angular js创建表单_如何优雅的使用 Angular 表单验证
随便说说,这一节可以跳过 去年参加 ngChine 2018 杭州开发者大会的时候记得有人问我: Worktile 是什么时候开始使用 Angular 的,我说是今年(2018年) 3 月份开始在新模 ...
- angular表单验证 1
表单验证 通常,我们都需要对用户的表单输入做验证,以保证数据的整体质量. Angular也有两种验证表单的形式: 使用属性验证,用于模板驱动表单: 使用验证器函数进行验证,用于响应式表单. 验证器(V ...
- angularjs表单验证_AngularJS表单验证
angularjs表单验证 We have updated this article for Angular 1.3 and the new ng-touched feature. 我们已经为Angu ...
- Angular响应式表单及表单验证
1. 什么是响应式表单? 响应式表单提供了一种模型驱动的方式来处理表单输入,其中的值会随时间而变化. 响应式表单使用显示的,不可变的方式,管理表单在特定时间点上的状态.对表单状态的每一次变更都会返回一 ...
- Angular JS 中的内置方法之表单验证
angular js 结合html5 可以实现强大的表单验证功能 关闭html5自带的表单验证功能可以用 转载于:https://www.cnblogs.com/Pikzas/p/9005861.ht ...
- angular学习的一些小笔记(中)之表单验证
表单验证 我去,我感觉我这个人其实还是一个很傻逼的一个人,老是因为拼错了一个单词或者怎么样就浪费我很长时间,这样真的不行不行,要正确对待这个问题,好了,说正题吧,angular也有表单验证minlen ...
- angular中的表单验证
angular中的表单验证很强大, 一共有5中验证信息,$valid,$invalid,$pristine,$dirty,$error. $valid-----当验证通过的时候,为true,不通过的时 ...
最新文章
- vim windows linux文件格式转换
- 2018-3-12论文(非结构网络中有价值信息数据挖掘)笔记二-----作者:关联规则的非结构网络有价值信息数据挖掘(看不懂,看不懂)
- kotlin中Int Byte的相互转换,常用
- Winform中选取指定文件夹并获取其下所有文件
- Linux下RabbitMQ服务器搭建
- github注册之后更新教程
- 设计模式(十一):从文Finder中认识组合模式(Composite Pattern)
- some daily
- base-64 字符串中的无效字符。_查找字符串中连续不重复最长字符串和长度的方法...
- Spring+hibernate+JSP实现Piano的数据库操作---1.目录结构+展示
- 条件运算符的嵌套问题
- 可靠的Windows版Redis
- [黑客入门]花无涯新手入门教程笔记
- 《COMPLETE MAYA PRO GRAMMIN G VOLUME II》导言
- springboot-1-搭建一个springboot项目
- switch游戏服务器设置
- 阿里面试官Redis把我问到哑口无言…
- c语言 函数 引用调用,C 引用方式调用函数
- 区块链的硬分叉和软分叉
- Python基础知识笔记
热门文章
- at89c2051 定时器用法 c语言编程资料,用AT89C2051单片机制作的厨房定时器
- 服务器虚拟化破解,VMware vSphere 7 虚拟化组件合集
- 计算机网络采用哪种,计算机网络有哪几种 四种计算机网络类型
- PyCharm 升级pip或者其他软件包的方法(简单版)
- ASEMI肖特基二极管MBR20200FCT特征,MBR20200FCT应用
- python填充红色_opencv之颜色过滤只留下图片中的红色区域操作
- vue路由组件强制刷新amp;amp;缓存更新
- UNITY实战进阶-科大讯飞TTS(离线语音合成) unity播放PCM格式的wav(不依赖第三方库)-7
- js 字符串比较大小
- AES加解密之ECB、CBC和CFB三种模式