一. 响应式表单
响应式表单提供对底层表单对象模型直接、显式的访问。它们与模板驱动表单相比,更加健壮:它们的可扩展性、可复用性和可测试性都更高。如果表单是你的应用程序的关键部分,或者使用响应式表单来构建应用,那就使用响应式表单。
使用 angular/forms 库中的 FormGroup, FormControl,FormArray,FormBuilder 等类构建出的数据对象就是响应式的表单, 在响应式的表单中,我们会在数据源里面进行各种操作,像添加校验等,在html文件中使用 formGroup,formGroupName,formControlName等将数据和视图进行绑定(需要引入ReactiveFormsModule)。
1. 使用表单控件的几个步骤:
定义及创建FormGroup;
配置每个Control的验证规则;
HTML添加FormControlName;
获取表单数据;
自定义验证规则;
FormBuilder;
也可以总结为两步:创建数据模型,使用指令将模板中的html元素连接到数据模型上;
数据模型是指一个用来保存表单数据的数据结构,它由定义在angular/forms模块中的三个类组成:
(1). FormControl
是构成表单的基本单位,通常情况下用来代表一个 input 元素,也可以代表更复杂的UI组件,比如日历、下拉选择框。FormControl保存着与其关联的html元素当前的值、元素的校验状态以及元素是否被修改过等信息
(2). FromGroup
既可以代表表单的一部分,也可以代表整个表单,是多个FormControl的集合,将多个FormControl的值和状态聚合在一起,如果其中一个formcontrol是无效的,那整个FromGroup就是无效的
(3). FormArray
FormArray和FromGroup类似,但是他有一个长度属性,一般来说FormGroup用来代表整个表单,或者表单字段的固定子集(比如一个FromGroup里有两个FormControl分别是起始时间和结束时间); FormArray通常代表一个可以增长的字段集合,比如表单中有一个email字段,一个用户可能有多个Email,所以我们可以让用户输入任意多个email字段。
export class ReactiveFormComponent implements OnInit {
userName: FormControl = new FormControl('Jon');
formModel: FormGroup = new FormGroup({ // FormGroup的构造函数是个对象
startTime: new FormControl(), // key: startTime
endTime: new FormControl()
)};
emails: FormArray = new FormArray([
// FormArray的构造函数是个数组,数组的每个元素是FormControl,与FormGroup不同的是,FormArray中的FormControl是没有相关的key的,通过数组下标来访问;
new FormControl('[email protected]')
new FormControl('[email protected]')
]);
2. 响应式表单中的指令
(1) 响应式表单的指令全部来自于ReactiveFoemsModule模块,我们在使用响应式表单上都会导入这个模块。
类名 | 指令 使用属性绑定时的指令 |
指令 使用属性名字来连接数据模型和Dom元素 |
FormGroup | formGroup | formGroupName |
FormControl | formControl | formControlName |
FormArray | formArrayName |
// formControl不能用在formGroup指令的内部,单独和input框绑定起来;若想把userName属性放进表单中来,就要把input框放进form元素标签内,并且用formControlName属性绑定。
export class ReactiveFormComponent implements OnInit {
formModel: FormGroup = new FormGroup({
dateRange: new FormGroup({
from: new FormmControl(),
to: new FormControl()
}),
emails: FormArray = new FormArray({ //FormArray中的FormControl没有名字,只有顺序号,所以一般情况下与ngFor指令一起使用;
new FormControl("")
new FormControl("")
})
});
uesrName: FormControl = new FormControl("Jay") // 此时uesrName属性是不在表单的这个数据模型里面的,若想放进表单里,userName: new FormControl("Jay")
constructor() {}
ngOnInit() {}
onSubmit() {
console.log(this.formModel.value);
}
addEmail() {
let emails = this.formModel.get("emails") as FormArray; //formModel.get("emails")拿到的是FormArray类型的对象,用as转型成formArray
emails.push(new FormControl())
}
}
(2)FormBuilder服务
当需要与多个表单打交道时,手动创建多个表单控件实例会非常繁琐。FormBuilder服务提供了一些便捷方法来生成表单控件,简化了定义表单数据结构的语法,就相当于Angular提供的一个工具。
通过以下步骤来实现这项服务:
①. 导入FormBuilder类,
②. 注入FormBuilder服务,
③. 生成表单内容。
export class ReactiveFormComponent implements OnInit {
formModel: FormGroup;
constructor( fb: FormBuilder ) {
this.formModel = fb.group({
dateRange: fb.group({
from: [''], // FormGroup还允许用数组来实例化一个formControl的实例,数组的第1个元素是formControl的初始值,第2个元素是校验方法,第3个元素是一个异步校验方法;多余的元素会被忽略。
to: ['']
}),
});
}
}
自定义验证器
响应式表单的校验逻辑还可以以返回一个ValidatorFn类的函数(自定义验证器)实现的。
function forbiddenNameValidator(value: string): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const rule = new RegExp(value,'i'); // 设定验证规则,i是忽略大小写的意思
const result = rule.test(control.value); //control.value是输入框的值,forbidden是正则结果
return result ? { 'forbiddenName': { value: control.value } } : null; //如果匹配成功,则返回对象
};
}
firstName:['',[forbiddenNameValidator('bob')]],
2. 模板驱动表单
简易理解:主要是html模板中使用指令(属性),适合简单的场景。对于html本身就有一些属性,比如最小值、最大值、规定type是number只能输入数字。
模板驱动表单依赖模板中的指令来创建和操作底层的对象模型,。它们对于向应用添加一个简单的表单非常有用。模板驱动的表单是我们实例化好一个类的数据之后,在html中使用 NgForm 指令后将数据和表单进行绑定,使用[(ngModel)]来将表单的数据和和视图进行双向绑定,NgForm 指令为 form 增补了一些额外特性。 它会控制那些带有 ngModel 指令和 name 属性的元素,监听他们的属性。添加校验时要是用指令的方式,适合固定的输入表单。
可以简单理解成响应式表单是动态的,模板驱动表单是静态的。模板驱动表单适用于页面比较固定,例如登录页面,可以使用模板驱动表单。响应式表单适用于动态页面,通常都是维护一个formGroup,任何想要添加进来进行验证的组件,只要绑定一个formControl,然后加入到formGroup里,接下来的状态就可以通过formGroup来获取了。