不同 | 响应式 | 模板驱动 |
---|---|---|
建立(表单模式) | 显式,在组件类中创建 例如:this.myForm = new FormGroup({}) |
隐式,由组件创建。 例如[(ngModel)]=“favoriteColor” |
数据模式 | 结构化 | 非结构化 |
可预测性 | 同步 | 异步 |
表单验证 | 函数 | 指令 |
可变性 | 不可变 | 可变 |
可伸缩性 | 访问底层 API | 在 API 之上的抽象 |
总结 | 响应式直接访问底层api性能更好,适用于复杂表单 | 模板驱动的底层原理相同,但是访问的时上层API适用于简单表单 |
html<表单>
写法一:
// 通过myForm变量与ts关联
// formControlName: 是输入指令,同formGroup 指令配合使用。
写法一的html也可以写成如下方式:
//等同于
------
写法二:
js部分
1.在app.moudle.ts中引入并注册
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
imports: [
FormsModule,
ReactiveFormsModule,
]
2.在需要使用的ts页面再次引入并使用
import { FormGroup,FormControl, Validators} from '@angular/forms';
// 引入FormGroup是监控整个表单
// 引入FormControl是监控表单控件
// 引入Validators是为了校验表单数据
export class AppComponent implements OnInit {
1.写法一:[FormGroup](对应上方html写法)
this.myForm = new FormGroup({ // 创建整个表单监控
firstName: new FormControl(''), // 创建单个组件监控
});
2.写法二:[formControl]
name = new FormControl('',Validators.required);
console.log(name.value); // ''
console.log(name.status); // 'INVALID'
this.name.setValue('Nancy'); // 修改控件的值
}
FormGroup:跟踪一组 FormControl 实例的值和有效性状态
FormGroup 把每个子 FormControl 的值聚合进一个对象,它的 key 是每个控件的名字。
它通过归集其子控件的状态值来计算出自己的状态。如果组中的任何一个控件是无效的,那么整个组就是无效的。
FormGroup 实例拥有和 FormControl 实例相同的属性(比如 value、untouched)和方法(比如 setValue()。
FormArray:跟踪一个控件数组的值和有效性状态
FormArray 聚合了数组中每个表单控件的值。它会根据其所有子控件的状态总结出自己的状态。
如果 FromArray 中的任何一个控件是无效的,那么整个数组也会变成无效的。
1.对表单内容进行分组fromGroup
2.form 标签所发出的 submit 事件是原生 DOM 事件,通过点击类型为 submit 的按钮可以触发本事件。
这还让用户可以用回车键来提交填完的表单。
/***
注意:上面这个代码片段中的按钮还附加了一个 disabled 绑定,用于在 myForm 无效时禁用该按钮。
目前还没有执行任何表单验证逻辑,因此该按钮始终是可用的。稍后的表单验证一节会讲解简单的表单验证。
***/
1.在app.moudle.ts中引入并注册
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
imports: [
FormsModule,
ReactiveFormsModule,
]
1.1.再在xx.ts部分用FormGroup定义表单:
import { FormGroup, FormControl } from '@angular/forms';
export class ProfileEditorComponent {
myForm = new FormGroup({
name: new FormControl(''),
age: new FormControl(''),
sex: new FormControl(''),
address: new FormGroup({ // address 此时不是 fromControl 而是 formGroup
street: new FormControl(''),
city: new FormControl(''),
state: new FormControl(''),
zip: new FormControl('')
})
});
}
1.1或者再在xx.ts部分用FormBuilder定义表单:
使用FormBuilder定义表单,来便捷的生成表单控件,也就是定义表单的简便方法
import { FormBuilder, Validators } from '@angular/forms';
constructor(private fb: FormBuilder) {
// FormBuilder 服务有三个方法:control()、group() 和 array()。
// 这些方法用于在组件类中分别生成 FormControl、FormGroup 和 FormArray。
this.myForm = this.fb.group({
name: ['', nameValidator()],
age: ['', ageValidator()],
sex: ['', sexValidator()],
address: this.fb.group({
province: ['', requiredValidator('请输入省')],
city: ['', requiredValidator('请输入市')],
district: ['', requiredValidator('请输入区')]
})
});
}
2.保存表单数据
// 当点击提交button时(type="submit"),会触发
import { FormBuilder, Validators } from '@angular/forms';
1.1 验证表单
把表单控件中的变量设置为必填:Validators.required
this.myForm = this.fb.group({
// 同步验证器
name: ['', [
Validators.required, //必填
Validators.minLength(4), //最少4个字
forbiddenNameValidator(/bob/i) // 禁止输入的名字中有bob
]],
age: ['', ageValidator()],
})
get nameVar() {
// 一定要有getter属性,html模板中nameVar.errors.required中的nameVar就是通过getter获取的
return this.heroForm.get('name');
}
// 或者在html上
名字必填
名字的长度不能小于4
名字不能包含bob
自定义规则
// 每一个表单控件都有valid/invalid(有效/无效)属性,为true说明满足验证条件
// *ngIf="name.invalid && (name.dirty || name.touched)"为true说明name的input框验证不通过,
// 并且dirty为true说明控件是输入过值的,而当控件失去焦点时,就会改变控件的 touched(碰过)状态。
// 确保用户还没有编辑过表单时不显示错误提示
1. 新建xx.ts文件,用来写自定义验证器
import { AbstractControl } from "@angular/forms";
export function nameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): {
[key: string]: any} | null => {
const forbidden = nameRe.test(control.value);
return forbidden ? {'forbiddenName': {value: control.value}} : null;
};
}
2.使用
import { nameValidator } from '../../上面定义验证器函数的文件名';
//在constructor中定义表单控件实例,
//并用内置验证器和自定义验证器始初化
this.myForm = this.fb.group({
// 同步验证器
name: ['', [
Validators.required, //必填
Validators.minLength(4), //最少4个字
forbiddenNameValidator(/bob/i) // 禁止输入的名字中有bob
nameValidator(/bob/i) // 自定义验证函数
]],
age: ['', ageValidator()],
})
//一定要加上这个getter属性,这样在模板中才能取到name,下面模板中name.errors中的name就是通过这个getter方法取到的
get nameVar() {
return this.myForm.get('name');
}
1. 新建xx.ts文件,用来写自定义验证器
// 在模板驱动表单中,不能直接访问 FormControl 实例。
// 所以不能像响应式表单中那样把验证器传进去,而应该在模板中添加一个指令。
@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;
}
}
2.使用
import { appForbiddenName } from '../../上面定义验证器函数的文件名';