在 Angular 中,提供了两种表单来处理用户的输入,模板驱动表单 和 响应式表单。
建立表单模型
响应式表单
前提条件:在需要使用响应式表单的组件所在的模块中引入
ReactiveFormsModule
最基本的响应式表单
Html
1 | <input type="text" class="form-control" [formControl]="nameControl"> |
Ts
1 | import { FormControl } from '@angular/forms'; |
此处为单个控件,使用响应式表单时需要引入 FormControl。
注: Html 模板中的 class="form-control" 代码只和样式有关,和响应式表单无关。
模板驱动表单
前提:在需要使用响应式表单的组件的对应的模块中引入
FormsModule
最基本的模板驱动表单
Html
1 | <input type="text" class="form-control" name="favorite" [(ngModel)]="color"> |
Ts
1 | ....//代码块 |
响应式表单
响应式表单适用于构建大型表单,且其跨代码的重用性强
控件分组
响应式表单只是展示一个控件,会使用到 FormControl。而响应式表单在项目中往往适用于大型表单,即表单中不会只存在一个表单控件。而存在多个控件时,需要对表单控件进行分组。在响应式表单中,对控件进行分组,需要引入并实例化 FormGroup,其代码如下所示。
Ts
1 | import { FormControl, FormGroup } from '@angular/forms'; |
Html
1 | <form [formGroup]="Charter" (ngSubmit)="consoleSubmit()"> |
FormControl 能让开发者管理单个控件,当存在控件分组时,FromGroup 实例能跟踪一组 FormControl 的状态。
在 Ts 代码中实例化 FromGroup 后,在 Html 中,将 Charter 这个 FormGroup 通过 FormGroup 指令绑定到 form 元素上。由 formControlName 指令提供的 formControlName 属性将每个输入框和 FormGroup 中的定义 FormControl 关联起来。
嵌套表单组
在响应式表单中,建立更加复杂的表单时,对表单信息进行分组,将相关联的消息放到一个组,将该组又放到一个更大的组中,即嵌套表单组。使用嵌套分组能让开发者更加易于实现和管理表单。
在填写个人信息表单时,地址是一个很常见的信息。在响应式表单中,地址是对表单进行分组的一个绝佳范例。其代码如下所示。
Ts
1 | ...//代码块 |
Html
1 | <form [formGroup]="Charter" (ngSubmit)="consoleSubmit()"> |
在上面代码中,address 为一个 FormGroup,在 Html 中通过 FormGroupName 指令将 address 这个 FormGroup 与视图关联起来。
FormBuilder 生成表单控件
在上面的 Ts 代码中实例化表单控件时,只有几个属性,一会是 new FormGroup(),一会是 new FormControl(),代码过于笨重,而 Angular 提供了 FormBuilder 服务来快捷生成表单。其代码如下所示
Ts
1 | import { FormBuilder } from '@angular/forms'; |
使用 FormBuilder 创建表单和使用 new FormGroup() 和 ngw FormControl() 创建表单结果是一样的,但其代码跟加的简洁。
FormBuilder服务有三个方法:control()、group()和array()
FormArray 管理动态表单
FormArry 是 FormGroup 的另一种选择,当开发者事先不知道子控件的具体数量是多少, FormArray 是一种很好的选择,它可以帮助开发者很好的管理匿名控件。
应用场景:当表单中存在组件变化时,如在 Charter (人物)表单中,添加人物的 enable (能力)属性,但是人物的 enable 能力不可能只有一个,存在多个,比如驾驶,观察,组织等,不确定有多少。而 FormArray 就是应用于这种场景,其代码如下所示
Ts
1 | import { FormArray, FormBuilder, Validators } from '@angular/forms'; |
Html
1 | <form [formGroup]="Charter" (ngSubmit)="consoleForm()"> |
其在浏览器页面中的效果(Html 代码中已移除样式类)如下所示

注意:在
Html中,关于响应式表单的指令一律小写开头,如formGroup,formControlName等,不能写成FormGroup,FormControlName等,若大写开头会报错或绑定不成功
在上面的 Ts 代码中,使用了FormArray 的 push 和 removeAt() 方法,FormArray 的常用方法如下表所示
| 方法 | 参数 | 描述 |
|---|---|---|
| at() | (index:number) | 获取指定位置的 FormControl |
| push() | (control:AbstractControl) | 在数组末尾添加一个 FromControl |
| insert() | (index:number,control:AbstractControl) | 在指定位置添加一个 FromControl |
| removeAt() | (index:number) | 移除指定位置的 FromControl |
| setControl() | (index:number,control:AbstractControl) | 替换指定位置的 FromControl |
| setValue | (value: any[]) | 设置 FormArray 中各个控件的值,数据结构不匹配时会报错(建议到 官网 查看) |
| patchValue | (value: any[]) | 设置 FormArray 中各个控件的值,数据结构不匹配时不会会报错(建议到 官网 查看) |
| resset() | (value:any[]) | 重置 FormArray 的值,并设置各个控件标记为 untouched 和 pristine 都为true |
| getRawValue() | () | 这个 FormArray 的聚合值,包括已禁用的控件 |
响应式表单验证
表单验证是表单中最重要的部分之一,对于一个表单,有一个完善的表单验证能有效的降低后台开发者的工作时间。并且在提交表单时,减少项目的报错(提交的表单数据不符合需求),提高用户体验。
Angular 提供的验证器函数
对于响应式表单,Angular 提供了一组常用的验证器函数,这些函数接收一个表单控件,验证并根据验证的结果返回一个空值(null,其代表验证通过)或错误对象。当然,HTML5 存在一些内置的属性,用来进行原生的验证,如 required,minLength,maxLength,pattern 等,其用法如下所示
Html
1 | <input type="text" name="name" formControlName="name" required> |
使用 Angular 提供的验证器函数时,需要在组件中导入 Validators 类,其基本用法如下所示。
Ts
1 | import { FormBuilder, Validators } from '@angular/forms'; |
使用 Angular 自带的 Validators 验证器,其提供的验证方案如下所示。
Validators.min(),要求控件大于等于某个值,一般用于验证数字
用法:const age=new FormControl(18,Validators.min(2))
Validators.max(),要求控件小于等于某个值,一般用于验证数字
用法:const age=new FormControl(0,Validators.max(2))
Validators.required,要求控件非空,一般用于验证input输入或select框
用法:const name=new FormControl('',Validators.required)
Validators.requiredTrue,要求控件值为真,一般用于验证checkbox
用法:const control=new FormControl('',Validators.requiredTrue)
Validators.email,要求控件的值为
用法:const owebEmail=new FormControl('',Validators.email)
Validators.minLength(),要求控件值的字符长度大于等于某个指定的长度,一般用于验证input的text输入类型
用法:const name=new FormControl('',Validators.minLength(8))
Validators.maxLength(),要求控件值的字符长度小于等于某个指定的长度,一般用于验证input的text输入类型
用法:const name=new FormControl('',Validators.maxLength(8))
Validators.pattern(),要求控件的值符合某种规则(正则表达式),一般用于验证input的text输入类型,判断其输入是否符合某种正则表达式
用法:const name=new FormControl('',Validators.pattern('[a-zA-Z]*')),验证 name 控件的值只包含字母或为空格
Validators.nullValidator,该验证器什么也不做
用法:const name=new FormControl('',Validators.nullValidator)
Validators.compose(),将多个验证器合并成一个
用法:const name=new FormControl('',Validators.compose([Validators.required,Validators.pattern('[a-zA-Z]*')])),验证 name 控件必须要有值且只包含字母
存在多个验证器时的另一种写法:const name=new FormControl('',[Validators.required,Validators.pattern('[a-zA-Z]*')]),直接去掉 Validators.compose()
Validators.asyncCompose(),将多个异步验证器合并成一个
自定义验证器函数
虽然 Angular 提供丰富的内置验证器函数,但是不能保证这些内置验证器函数能用于所有的表单,这时,就需要开发者创建自定义验证器。
假如需要定义一个 input 的 text 框,禁止在框中出现 jack 的字符。其验证器代码如下所示
forbidden.directive.ts
1 | export function forbiddenValitors(nameRe:RegExp):ValidatorFn{ |
在响应式表单中使用自定义验证器
Ts
1 | import { forbiddenValitors } from '../forbidden.directive' |
使用了自定义验证器后,在表单的 name 控制器中输入 jack 时,表单为 invalid 状态。
验证时错误提示
在表单中,用户的输入不符合要求时,表单一般都会提示错误(提高用户体验和告诉用户错在什么地方)。响应式表单中也可以实现该功能。代码如下所示
Ts
1 | ....//代码块 |
Html
1 | 姓名:<input type="text" name="name" formControlName="name"> |
异步验证
异步验证也是表单验证中重要的一部分,其应用的场景一般需要进行远程通讯。比如用户在使用表单进行注册时,规定用户名不能和已有的用户名相同,由于前端不知道已有的用户名有哪些,这就需要将已经输入的用户名去和后台数据库里面的用户名相匹配。
其异步验证代码如下所示
async.service.ts(返回 Observable 对象,模拟 http 请求)
1 | import { Injectable } from '@angular/core'; |
asyc-name-validator.ts(定义异步验证器)
1 | import { Injectable } from '@angular/core'; |
reactive.component.ts(使用异步验证器)
1 | import { FormBuilder } from '@angular/forms'; |
当在页面中的 name input 框中输入 jack、lucy 或 bing 时,页面中表单状态为 INVALID