angular表单
angular表单分为两类:
1. 模板式表单:表单的数据模型是通过组件模板中的相关指令来定义的,因为使用这种方式定义表单的数据模型时,我们会受限于HTML的语法,所以,模板驱动方式只适合用于一些简单的场景。
2. 响应式表单:使用响应式表单时,你通过编写TypeScript代码而不是Html代码来创建一个底层的数据模型,在这个模型定义好以后,你使用一些特定的指令,将模板上的html元素与底层的数据模型连接在一起。
模板式表单与响应式表单的区别:
- 不管是哪种表单,都有一个对应的数据模型来存储表单的数据。在模板式表单中,数据模型是由angular基于你组件模板中的指令隐式创建的。而在响应式表单中,你通过编码明确的创建数据模型然后将模板上的html元素与底层的数据模型连接在一起。
- 数据模型并不是一个任意的对象,它是一个由angular/forms模块中的一些特定的类,如FormControl, FormGroup, FormArray等组成的。在模板式表单中,你是不能直接访问到这些类的。
- 响应式表单并不会替你生成html,模板仍然需要你自己来编写。
- 模板式表单引入FormsModule,响应式表单引入ReactiveFormsModule(在app.module.ts文件中)
模板式表单
模板式表单指令(来源于FormsModule):
- NgForm:代表整个表单,在angular中会被自动的添加到每个form表单上,隐式的创建一个FormGroup类的实例,这个类用来代表表单的数据模型,并且存储表单的数据。
- NgModel:在form中用于标记一个html元素,成为表单模型的一部分,并将值添加到表单的数据模型中。它会隐式的创建一个FormControl类的实例,来代表字段的数据模型,并使用FormControl类的对象来存储的字段的值。
- NgModelGroup:代表表单的一部分,允许将表单的一些字段组装在一起,形成更清晰的层次关系。它也会隐式创建一个FormGroup的实例,这个实例会在NgForm对象的value属性中表现为一个嵌套对象,FormGroup内部的子属性都会变成嵌套对象的子属性。
NgForm可使用在form表单外(eg: ‘div ngForm’ 与’form’相等)
如果不希望angular处理表单,需明确在form标签上添加ngNoForm
注:在元素中是ngModel而非([ngModel]),写ngModel时,需为此元素指定name属性,这个name指会成为NgForm对象的value属性对应的对象中的一个属性。
这三个指令都可被本地变量引用。
//ngForm可被本地变量引用,便于操作
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value, myForm.valid)" novalidate>
<div>用户名:<input ngModel required minlength="6" name="username" type="text" (input)="onMobileInput(myForm)"></div>
<div [hidden]="mobileValid || mobileUntouched">
<div [hidden]="!myForm.form.hasError('required','username')">
用户名是必填项
</div>
<div [hidden]="!myForm.form.hasError('minlength','username')">
用户名最小长度是6
</div>
</div>
<div>手机号:<input ngModel mobile name="mobile" type="number"></div>
<div [hidden]="!myForm.form.hasError('mobile','mobile')">
请输入正确的手机号
</div>
<!-- ngModelGroup合为一起,最后form的数据为passwordsGroup: {password: 1234, pconfirm: 1234} -->
<div ngModelGroup="passwordsGroup" equal>
<div>密码:<input ngModel minlength="6" name="password" type="password"></div>
<div [hidden]="!myForm.form.hasError('minlength',['passwordsGroup','password'])">
密码最小长度是6
</div>
<div>确认密码:<input ngModel name="pconfirm" type="password"></div>
<div [hidden]="!myForm.form.hasError('equal','passwordsGroup')">
{{myForm.form.getError('equal','passwordsGroup')?.descxxx}}
</div>
</div>
<button type="submit">注册</button>
</form>
响应式表单
创建响应式表单分两步:
- 使用编码来创建一个数据模型(数据模型指一个用来保存表单数据的数据结构)
- 使用指令将模板中的html元素连接到数据模型上。
数据模型(简称模型)由定义在angular/forms中的以下三个类组成:
- FormControl:保存与其关联的html元素的当前值及较难状态。
- FormGroup: 即可代表表单的一部分又可代表整个form表单,是多个FormControl的集合。如果有一个FormControl是无效的,则整个FormGroup便是无效的。
- FormArray:与formGroup类似,它有一个长度属性,FormGroup用来代表整个表单或者表单字段的固定子集,formArray通常用来代表一个可以增长的字段集合。
<!-- 数据模型 -->
formModel:FormGroup = new FormGroup({
username: new FormControl("aaa"),
dateRange: new FormGroup({
from: new FormControl(),
to: new FormControl()
}),
emails: new FormArray([
new FormControl("a@a.com"),
new FormControl("b@b.com")
])
});
onSubmit(){
console.log(this.formModel.value);
}
addEmail(){
let emails = this.formModel.get("emails") as FormArray;
emails.push(new FormControl());
}
<!-- 模板 -->
<form [formGroup]="formModel" (submit)="onSubmit()">
<input formControlName="username">
<div formGroupName="dateRange">
起始日期:<input type="date" formControlName="from">
截止日期:<input type="date" formControlName="to">
</div>
<div>
<ul formArrayName="emails">
<li *ngFor="let e of this.formModel.get('emails').controls; let i=index;">
<input type="text" [formControlName]="i">
</li>
</ul>
<button type="button" (click)="addEmail()">增加Email</button>
</div>
<div>
<button type="submit">保存</button>
</div>
</form>
响应式表单指令:(响应式表单指令不可使用本地变量来引用)
可以使用formBuilder工具快速的定义数据模型
constructor(fb: FormBuilder) {
//FormBuilder有三个方法:group、
this.formModel = fb.group({
//name: [初始值,校验方法,异步的校验方法];
username: ['', [Validators.required, Validators.minLength(6)]],
mobile: ['', mobileValidator, mobileAsyncValidator],
passwordsGroup: fb.group({
password: ['', Validators.minLength(6)],
pconfirm: ['']
//equalValidator是对整个passwordsGroup的校验。
}, {validator: equalValidator})
})
}
表单校验
angular的校验器:一个校验函数
格式为:xxx(control: AbstractControl): {[key: string]: any} {校验方法}
angular提供的默认校验有:Validators.required(必填),minLength(6)
//判断一个校验是否合法: 校验的是username字段的所有校验,任一一项校验为false,则为false
isValid:boolean = this.formModel.get('username').valid;
//获取校验错误的校验信息:
errors: any =this.formModel.get('username').errors;
//手机校验
mobileValidator(control: FormControl): any {
var myreq = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
let valid = myreq.test(control.value);
return valid ? null : {mobile: true};
}
//密码与确认密码校验
equalValidator(group: FormGroup): any {
let password:FormControl = group.get('password') as FormControl;
let pconfirm:FormControl = group.get('pconfirm') as FormControl;
let valid:boolean = false;
if(password && pconfirm){
valid = (password.value === pconfirm.value);
}
// console.log("密码 是否校验通过: " + valid);
return valid ? null : {equal: {description:'密码和确认密码不匹配!'}};
}