Angular表单
在Angular中,表单有两种类型,分别为模板驱动和模型驱动。
一、模板驱动
1.概述
表单的控制逻辑写在组件模板中,适合简单的表单类型。
快速上手
1)引入依赖模块FormsModule
import {FormsModule} from '@angular/forms'
@NgModule({
imports:[FormsModule],
})
export class AppModule{}
2)将DOM表单转换为ngForm
<form #f="ngForm" (submit)="onSubmit(f)"></form>
3)声明表单字段为ngModel
<form #f="ngForm" (submit)="onSubmit(f)">
<input type="text" name="username" ngModel/>
<button>提交</button>
</form>
4)获取表单字段值
import {NgForm} from "@angular/forms"
export class AppComponent{
onSubmit(form:NgForm){
console.log(form.value.username)
}
}
2.表单分组
<from #f="ngForm" (submit)="onSubmit(f)">
<div ngModelGroup="user">
//<ng-container \ngModelGroup="user">
<input type="text" name="username" ngModel/>
</div>
//</ng-container>
<div ngModelGroup="contact">
<input type="text" name="phone" ngModel/>
</div>
<button>
提交
</button>
</from>
//使用时是form.value.user.username
3.表单验证
- required 必填字段
- minlength 字段最小长度
- maxlength 字段最大长度
- pattern 验证正则 例如:pattern='\d' 匹配一个数值
<form #f="ngForm" (submit)="onSubmit(f)">
<input type="text" name="username" ngModel required pattern="\d"/>
<button>提交</button>
</form>
export class AppComponent{
onSubmit(form:NgForm){
//查看表单整体是否验证通过
console.log(form.valid)
}
}
<!--表单整体未通过验证时禁用提交表单-->
<button type="submit" [disabled]="f.invalid">提交</button>
在组件模板中显示表单项未通过时的错误信息。
<form #f="ngForm" (submit)="onSubmit(f)">
<input #username="ngModel"/>
<div *ngIf="username.touched && !username.valid && username.errors">
<div>{{username.errors|json}}</div>
<div *ngIf="username.errors.required">请填写用户名</div>
<div *ngIf="username.errors.pattern">不符合正则规则</dvi>
</div>
</form>
指定表单项未通过验证时的样式。
input .ng-touched .ng-invalid{
border:2px solid red;
}
二、模型驱动
1.概述
表单的控制逻辑写在组件类中,对验证逻辑拥有更多的控制权,适合复杂的表单的类型。
在模型驱动表中,表单字段需要是FormControll类的实例,实例对象可以验证表单字段中的值,值是否被修改过等等。
一组表单字段构成整个表单,整个表单需要是FormGroup类的实例,它可以对表单进行整体验证。
1)FormControl:表单组中的一个表单项
2)FormGroup:表单组,表单至少是一个FormGroup
3)FormArray:用于复杂表单,可以动态添加表单项或表单组,在表单验证时,FormArray中有一项没通过,整体没通过。
快速上手
1)引入ReactiveFormsModule
import {ReactiveFormModule} from '@angular/forms'
@NgModule({imports:[ReactiveFormsModule]})
export class AppModule{}
2)在组件类中创建FormGroup表单控制对象
import {FormControl,FormGroup} from '@angular/forms'
export class AppComponent{
contactForm:FormGroup=new FormGroup({
name:new FormControl(),
phone:new FormControl()
})
}
3)关联组件模板中的表单
<form [formGroup]="contactForm" (submit)="onSubmit()">
<input type="text" formControlName="name"/>
<input type="text" formControlName="phone"/>
<button>提交</button>
</form>
4)获取表单值
export class AppComponent{
onSubmit(){
console.log(this.contactForm.value)
}
}
5)设置表单默认值
contactForm:FormGroup=new FormGroup({
name:new FormControl("name1"),
phone:new FormControl(123456789)
});
6)表单分组
contactForm:FormGroup=new FormGroup({
fullName:New FormGroup({
firstName:new FormControl(),
lastName:new FormControl()
}),
phone:new FormControl()
})
<form [formGroup]="contactForm" (submit)="onSubmit()">
<div formGroupName="fullName">
<input type="text" formControlName="firstName"/>
<input type="text" formControlName="lastName"/>
</div>
<input type="text" formControlName="phone"/>
<button>提交</button>
</form>
onSubmit(){
console.log(this.contactForm.value.name.username)
console.log(this.contactForm.get(["fullName","firstName"])?.value)
}
2.FormArray
需求:在页面中默认显示一组联系方式,通过点击按钮可以添加更多联系方式组。
import {Component,OnInit} from "@angular/core"
import {FormArray,FormControl,FormGroup} from "@angular/forms"
@Component({
selector:"app-root",
templateUrl:"./app.component.html",
styles:[]
})
export class AppComponent implements OnInit{
//表单
contactForm:FormGroup=new FormGroup({
contacts:new FormArray([])
})
get contacts(){
return this.contactForm.get("contacts") as FormArray
}
removeContact(index:number){
this.contacts.removeAt(index)
}
//添加联系方式
addContact(){
//联系方式
const myContact:FormGroup=new FormGroup({
name:new FormControl(),
address:new FormControl(),
phone:new FormControl()
})
this.contacts.push(myContact);
}
ngOnInit():void{
this.addContact();
}
onSubmit(){
console.log(this.contactForm.value)
}
}
<form [fromGroup]="contactFrom">
<div formArrayName="contacts">
<div *ngFor="let contact of contacts.controls;let i=index" [formGroupName]="i">
<input type="text" formControlName="name"/>
<input type="text" formControlName="phone"/>
<input type="text" formControlName="address"/>
<button (click)="removeContact(i)">删除联系方式</button>
</div>
</div>
<button (click)="addContacts()">添加联系方式</button>
</form>
3.内置表单验证器
1)使用内置验证器提供的验证规则验证表单字段
import {FormControl,FormGroup,Validators} from "@angular/forms"
contactForm:FormGroup=new FormGroup({
new:new FormControl("默认值",[
Validators.required,
Validators.minLength(2)
]),
})
2)获取整体表单是否验证通过
onSubmit(){
console.log(this.contactForm.valid)
}
<!---表单整体来验证通过时禁用表单按钮-->
<button [disabled]="contactForm.invalid">提交</button>
3)在组件模板中显示为验证通过时的错误信息
get name(){
return this.contactForm.get("name")!
}
<form [formGroup]="contactForm" (submit)="onSubmit()">
<input type="text" formControlName="name"/>
<div *ngIf="name.touched && name.invalid && name.errors">
<div *ngIf="name.errors.required">请填写姓名</div>
<div *ngIf="name.errors.maxlength">
姓名长度不能大于
{{name.errors.maxlength.requiredLength}}实际填写长度为
{{name.errors.maxlength.actualLength}}
</div>
<div>
<button [disabled]="contactForm.invalid">提交</button>
</form>
4.自定义同步表单验证器
1)自定义验证器的类型是TypeScript类
2)类中包含具体的验证方法,验证方法必须为静态方法
3)验证方法有一个参数control,类型为AbstractControl,其实就是FormControl类的实例对象的类型
4)如果验证成功,返回null
5)如果验证失败,返回对象,对象中的属性即为验证标识,值为true,标识该项验证失败
6)验证方法的返回值为ValidationErrors|null
import {AbstractControl,ValidationErrors} from '@angular/forms'
export class NameValidators{
//字段值中不能包含空格
static cannotContainSpace(control:AbstractControl):ValidationErrors|null{
//验证未通过
if(/\s/.test(control.value)){//验证客户输入是否包含空格
return {cannotContainSpace:true}
}
return null
}
}
import {NameValidators} from "./Name.validators"
contactForm:FormGroup=new FormGroup({
name:new FormControl("",[
Validators.required,
NameValidators.cannotContainSpace
])
})
<form [formGroup]="contactForm" (submit)="onSubmit()">
<input type="text" formControlName="name"/>
<div *ngIf="name.touched && name.invalid && name.errors">
<div *ngIf="name.errors.required">请填写姓名</div>
<div *ngIf="name.errors.maxlength">
姓名长度不能大于
{{name.errors.maxlength.requiredLength}}实际填写长度为
{{name.errors.maxlength.actualLength}}
</div>
<div *ngIf="name.errors.cannotContainSpace">名字中不能包含空格</div>
<div>
<button [disabled]="contactForm.invalid">提交</button>
</form>
5.自定义异步表单验证器
1)自定义验证器的类型是TypeScript类
2)类中包含具体的验证方法,验证方法必须为静态方法
3)验证方法有一个参数control,类型为AbstractControl,其实就是FormControl类的实例对象的类型
4)如果验证成功,返回null
5)如果验证失败,返回对象,对象中的属性即为验证标识,值为true,标识该项验证失败
6)验证方法的返回值为ValidationErrors|null
import {AbstractControl,ValidationErrors} from '@angular/forms'
export class MyValidators{
//字段值中不能包含空格
static shoudBeUnique(control:AbstractControl):Promise<ValidationErrors|null>{
return new Promise(function(resolve){
//向后台发送请求
setTimeout(function(){
if(control.value==="admin"){
resolve({shouldBeUnique:true})
}else{
resolve(null)
}
},2000)
})
}
}
import {NameValidators} from "./Name.validators"
contactForm:FormGroup=new FormGroup({
name:new FormControl("",[
Validators.required
],MyValidators.shouldBeUnique)
})
onPatchValue(){
this.form.patchValue({
firstName:"test"
})
}
onSetValue(){
this.form.setValue({
firstName:"1234",
lastName:"aaa"
})
}
ngOnInit():void{ this.form.get('lastName')?.valueChanges.subscribe((value)=>{
console.log(value)
})
}
onRest(){
this.form.reset();
}
<form [formGroup]="contactForm" (submit)="onSubmit()">
<input type="text" formControlName="name"/>
<div *ngIf="name.touched && name.invalid && name.errors">
<div *ngIf="name.errors.required">请填写姓名</div>
<div *ngIf="name.errors.maxlength">
姓名长度不能大于
{{name.errors.maxlength.requiredLength}}实际填写长度为
{{name.errors.maxlength.actualLength}}
</div>
<div *ngIf="name.errors.shouldBeUnique">名字已经存在</div>
<div>
<div *ngIf="name.pending">正在验证</div>
<button (click)="onPatchValue">patchValue</button>
<button (click)="onSetValue()">setValue</button>
<button (click)="onReset"><button>
<button [disabled]="contactForm.invalid">提交</button>
</form>
6.FormBuilder
创建表单的快捷方式。
1)this.fb.control:表单项
2)this.fb.group:表单组,表单至少是一个FormGroup
3)this.fb.array:用于复杂表单,可以动态添加表单项或表单组,在表单验证时,FormArray中有一项没通过,整体没通过。
import {FormBuilder,FormGroup,Validators} from "@angular/forms"
export class AppComponent{
contactForm:FormGroup
constructor(private fb:FormBuilder){
this.contactForm=this.fb.group({
fullName:this.fb.group({
firstName:["2",[Validators.required]],
//fristName:this.fb.control({})
lastName:[""]
}),
phone:[]
})
}
}
7.其他
1)patchValue:设置表单控件的值(可以设置全部,也可以设置其中某一个,其他不受影响)
2)setValue:设置表单控件的值(设置全部,不能排除任何一个)
3)valueChanges:当表单控件的值发生变化时被触发的事件
4)reset:表单内容置空