##模板式表单 需要引入FormsModule,引入该模块后,在该模块下的所有表单都默认被装饰为模板模式。若仍要使用HTML模式,则指定<form ngNoForm>
。
| ------------- |:-------------:| -----------------------|
| NgForm | FormGroup | 定义在表单<form>
标签上,指向整个表单 |
| NgModel | FormControl | 定义在表单行上,指向单行表单数据 |
| NgModelGroup | FormGroup | 定义div包含一组关联的表单行,统一处理 |
代码示例:
//NgForm 定义整个表单 同时指定表单提交事件,angular的表单不会再触发默认的表单提交
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value)">
<div>用户名:<input ngModel name="username" type="text"></div>//通过ngModel和name属性来绑定表单的元素
<div>手机号:<input ngModel name="mobile" type="number"></div>
<div ngModelGroup="passwordsGroup">//通过ngModelGroup来绑定多个表单元素,被绑定的表单元素会作为group的属性
<div>密码:<input ngModel name="password" type="password"></div>
<div>确认密码:<input ngModel name="pconfirm" type="password"></div>
</div>
<button type="submit">注册</button>
</form>
复制代码
##响应式表单 -FormControl-定义到表单行输入数据username: FormControl = new FormControl("xxx")
如代码所示,前面模板式表单中的ngModel定义的username实质就是定义了如上一行代码
-FormGroup-定义了整个表单或多个FormControl集合
formModel: FromGroup = new FormGroup({
from: new FormControl(),
to: new FormControl()
});
复制代码
-FormArray-定义了一个可变长的集合,与FormGroup不同的是,不能通过属性名来访问,而是通过下标来获取,从0开始。
email: FormArray = new FormArray([
new FromControl("aaaaa");
new FromControl("bbbbb");
]);
复制代码
代码示例:
<form [formGroup]="fromModel" (submit)="onSubmit()">
<input formControlName="username">
<div fromGroupName="dateRange">
开始日期:<input type="date" formControlName="from">
截止日期:<input type="date" formControlName="to">
</div>
<div>
<ul fromArrayName="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>
复制代码
fromModel: FromGroup = new FormGroup({
username: new FromControl("aaa"),
dateRange: new FormGroup({
from: new FormControl(),
to: new FormControl()
}),
emails: new FormArray([
new FromControl("aaaaa");
new FromControl("bbbbb");
])
});
addEmail(){
let emails = this.formModel.get("emails") as FormArray;
eamils.push(new FromControl);
}
复制代码
###FormBuilder的使用 constructor(fb: FormBuilder){ this.formModel = fb.group({ username: ['',校验方法], mobile: [''], passwordsGroup: fb.group({ password: [''], pconfirm: [''] }) },{'校验方法'}); } 使用FormBuilder可以简洁构造表单模型的代码。
##表单校验 校验器
1、使用预定义的校验器
constructor(fb: FormBuilder){
this.formModel = fb.group({
username: ['',[Validators.required,Validators.minLength(6)]],//必填,最小长度是6
mobile: [''],
passwordsGroup: fb.group({
password: [''],
pconfirm: ['']
})
});
}
onSubmit(){
let isValid: boolean = this.formModel.get("username").valid;//校验结果
let errors: ant = this.formModel.get("username").errors;//校验错误信息
}
复制代码
2、自定义校验器 xxxxx(control: AbstractContol):{[key: string]: ant}{return null}
//formcontrol的校验
mobileValidator(control: FormControl): any{
var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
let valid = myreg.test(control.value);
return valid ? null : {mobile : true};
//校验失败的时候返回空,成功返回对象和值
}
//formgroup的校验
equalValidator(group: FormGroup): any{
let password:FromControl = group.get("password") as FormControl;
let pconfirm:FromControl = group.get("pconfirm") as FormControl;
let valid: boolean = (password.value === pconfirm.value);
return valid ? null : {equ: {info:"密码和确认密码不一致"}}
}
//使用校验器
constructor(fb: FormBuilder){
this.formModel = fb.group({
username: ['',[Validators.required,Validators.minLength(6)]],//必填,最小长度是6
mobile: ['',this.mobileValidator],
passwordsGroup: fb.group({
password: [''],
pconfirm: ['']
},{validator: this.equalValidators})
});
}
复制代码
通用的校验器可以放到一个单独的ts文件中,作为公用的校验方法。
声明全局方法的时候使用 export function xxx(){}
对整个表单的校验结果是this.formModel.valid
,只有所有的校验都成功的时候才会返回true
;
表单错误信息显示:
<div>用户名:<input formControlName="username" type="text"></div>
<div [hidden]="!formModel.hasError('required','username')">
用户名是必填项</div>
<div [hidden]="!formModel.hasError('minlength','username')">
用户名最小长度是6</div>
<div>手机号:<input formControlName="mobile" type="text"></div>
<div [hidden]="!formModel.hasError('mobile','mobile')">
请输入正确的手机号</div>
<div formGroupName="passwordsGroup">
<div>密码:<input formControlName="password" type="password"></div>
<div [hidden]="!formModel.hasError('minlength',['passwordsGroup','password'])">
密码最小长度是6</div>//在对formgroup中的formcontrol校验的时候要注意
<div>确认密码:<input formControlName="pconfirm" type="password"></div>
<div [hidden]="!formModel.hasError('equ','passwordsGroup')">
{{formModel.geterror('equ','passwordsGroup')?.info}}</div>
</div>
复制代码
异步校验器username: ['',校验方法,异步校验方法]
在bulider里面添加第三个函数,可以为需要校验的项新增一个异步的校验器,而校验的结果可以通过xxx(表单的formGroup).status来确认。
status有三个值 invalid
pending
valid
invalid状态表示未被校验通过
pending状态即表示当前异步校验器仍在校验过程中
valid状态表示校验通过
###状态字段 touched
和untouched
当前formcontrol是否被点击过,若表单未被用户使用访问的时候,即不显示错误信息
<div>用户名:<input formControlName="username" type="text"></div>
<div [hidden]="formModel.get('username').valid || formModel.get('username').untouched">
<div [hidden]="!formModel.hasError('required','username')">
用户名是必填项</div>
<div [hidden]="!formModel.hasError('minlength','username')">
用户名最小长度是6</div>
</div>
复制代码
pristine
和dirty
若字段的值未被用户修改过,则pristine为true,dirty为false。否则为反。
<div>手机号:<input formControlName="mobile" type="text"></div>
<div [hidden]="formModel.get('mobile'.valid || formModel.get('mobile').pristine)">
<div [hidden]="!formModel.hasError('mobile','mobile')">
请输入正确的手机号</div>
</div>
复制代码
pending
当一个字段处于异步校验的时候,pending值为true
<div>手机号:<input formControlName="mobile" type="text"></div>
<div [hidden]="formModel.get('mobile'.valid || formModel.get('mobile').pristine)">
<div [hidden]="!formModel.hasError('mobile','mobile')">
请输入正确的手机号</div>
</div>
<div [hidden]="!formModel.get('mobile').pending">
正在校验手机合法性
</div>
复制代码
###状态样式自定义 可以对ng-valid
ng-untouched
ng-pending
等验证状态进行修改
或者自己对属性进行绑定:<input [class.hasError]="formModel.get('username').invalid && formModel.get('username').touched" type="text" formControlName="username">
当表单未验证通过且被用户触碰过,添加上一个hasError的自定义样式
##自定义指令 ng g directive xxxx
新建一个指令文件
@Directive({
selector:'[xxxxx]',//在模板文件中使用时候直接使用xxxxx在标签属性中
providers:[{provide:NG_VALIDATORS,useValue:xxxxFucntion,multi: true}]//provide的token是固定的,useValue指向方法,multi表示一个token下是否可以挂多个值
})复制代码