Angular-表单
Angular
# 模板式表单
表单的数据模型是通过组件模板中的相关指令来定义的,因为使用这种方式定义表单的数据模型时, 我们会受限于HTML的语法,所以,模板驱动方式只适合用于一些简单的场景。
需要在app.module.ts中引入:
imports: [
FormsModule
]
1
2
3
2
3
# NgForm / ngNoForm
简单使用:
<div ngForm>
</div>
<form ngNoForm>
</form>
1
2
3
4
5
2
3
4
5
取值:
<form #myForm="ngForm">
</form>
<div>
{{myForm.value | json}}
</div>
1
2
3
4
5
6
2
3
4
5
6
提交:
<form #myForm="ngForm" (onSubmit)="onSubmit(myForm.value)">
<button type="submit">注册</button>
</form>
1
2
3
2
3
# NgModel
简单使用:
<form #myForm="ngForm" (onSubmit)="onSubmit(myForm.value)">
<div>用户名:<input ngModel name="username" type="text"></div>
<button type="submit">注册</button>
</form>
1
2
3
4
2
3
4
取值:
<form #myForm="ngForm" (onSubmit)="onSubmit(myForm.value)">
<div>用户名:<input #username="ngModel" ngModel name="username" type="text"></div>
<button type="submit">注册</button>
</form>
<div>
{{username.value}}
</div>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# NgModelGroup
简单使用:
<div ngModelGroup="userInfo">
<div>用户名:<input #username="ngModel" ngModel name="username" type="text"></div>
</div>
<div>
{{username.value}} <!-- {"userInfo": {"username": ""}} -->
</div>
1
2
3
4
5
6
7
2
3
4
5
6
7
# 样例
html:
<form #myForm="ngForm" (onSubmit)="onSubmit(myForm.value)">
<div>用户名:<input ngModel name="username" type="text"></div>
<div>手机号:<input ngModel name="mobile" type="number"></div>
<div ngModelGroup="passwordsGroup">
<div>密码:<input ngModel name="password" type="password"></div>
<div>确认密码:<input ngModel name="pconfirm" type="password"></div>
</div>
<button type="submit">注册</button>
</form>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
component:
onSubmit(value: any) {
console.log(value);
}
1
2
3
2
3
# 响应式表单
使用响应式表单时,那你通过编写TypeScript代码而不是Html代码来创建一个底层的数据模型, 在这个模型定义好以后,你使用一些特定的指令,将模板上的html元素与底层的数据模型连接在 一起。
需要在app.module.ts中引入:
imports: [
ReactiveFormsModule
]
1
2
3
2
3
# FormGroup
html
<form [formGroup]="formModel" (submit)="onSubmit()">
<div>
<button type="submit">保存</button>
</div>
</form>
1
2
3
4
5
2
3
4
5
component
formModel: FormGroup = new FormGroup ({});
onSubmit() {
console.log(this.formModel.value);
}
1
2
3
4
5
2
3
4
5
# FormControl
html
<form [formGroup]="formModel" (submit)="onSubmit()">
<input formControlName="username">
<div formGroupName="dateRange">
起始日期:<input type="date" formControlName="from">
截止日期:<input type="date" formControlName="to">
</div>
<div>
<button type="submit">保存</button>
</div>
</form>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
component
formModel: FormGroup = new FormGroup ({
username: new FormControl('aaa'),
dateRange: new FormGroup({
from: new FormControl(),
to: new FormControl()
})
});
1
2
3
4
5
6
7
2
3
4
5
6
7
# FormArray
html
<form [formGroup]="formModel" (submit)="onSubmit()">
<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
component
formModel: FormGroup = new FormGroup ({
dateRange: new FormGroup({
from: new FormControl(),
to: new FormControl()
}),
emails: new FormArray({
new FormControl("a@a.com"),
new FormControl("b@b.com")
})
});
addEmail() {
let emails = this.formModel.get('emails') as FormArray;
emails.push(new FormControl());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 样例
html
<form [FormGroup]="formModel" (onSubmit)="onSubmit()">
<div>用户名:<input type="text" formControlName="username"></div>
<div>手机号:<input type="number" formControlName="mobile"></div>
<div formGroupName="passwordsGroup">
<div>密码:<input type="password" formControlName="password"></div>
<div>确认密码:<input type="password" formControlName="pconfirm"></div>
</div>
<button type="submit">注册</button>
</form>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
component
formModel: FormGroup;
constructor() {
this.formModel = new FormGroup ({
username: new FormControl(),
mobile: new FormControl(),
passwordsGroup: new FormGroup({
password: new FormControl(),
pconfirm: new FormControl()
})
});
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# FromBuilder
通过FromBuilder简化代码
formModel: FormGroup;
constructor(fb: FormBuilder) {
this.formModel = fb.group ({
username: [''],
mobile: [''],
passwordsGroup: fb.group({
password: [''],
pconfirm: ['']
})
});
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 表单验证
html
<form [FormGroup]="formModel" (onSubmit)="onSubmit()">
<div>用户名:<input type="text" formControlName="username"></div>
<div [hidden]="!formModel.hasError('required', 'username')">
用户名是必填项
</div>
<div [hidden]="!formModel.hasError('minLength', 'username')">
用户名最小长度是6
</div>
<div>手机号:<input type="number" formControlName="mobile"></div>
<div [hidden]="!formModel.hasError('mobile', 'mobile')">
请输入正确的手机号
</div>
<div formGroupName="passwordsGroup">
<div>密码:<input type="password" formControlName="password"></div>
<div [hidden]="!formModel.hasError('minLength', ['passwordsGroup', ['password']])">
密码最小长度是6
</div>
<div>确认密码:<input type="password" formControlName="pconfirm"></div>
<div [hidden]="!formModel.hasError('equal', 'passwordsGroup')">
{{formModel.getError('equal', 'passwordsGroup')?.descxxx}}
</div>
</div>
<button type="submit">注册</button>
</form>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
component
// 可以将以下angular校验器抽取到一个ts文件中
mobileValidator(control: FormControl): any {
const myreq = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
const valid = myreq.test(control.calue);
console.log('mobile的校验结果是:' + valid);
return valid ? null : {mobile: true};
}
mobileAsyncValidator(control: FormControl): any {
const myreq = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\d{8})$/;
const valid = myreq.test(control.calue);
console.log('mobile的校验结果是:' + valid);
// 模拟异步
return Observable.of(valid ? null : {mobile: true}).delay(5000);
}
equalValidator(group: FormGroup): any {
const password: FormControl = group.get('password') as FormControl;
const pconfirm: FormControl = group.get('pconfirm') as FormControl;
const valid: boolean = (password.value === pconfirm.value);
console.log('密码的校验结果是:' + valid);
return valid ? null : {equal: {descxxx: '密码和确认密码不匹配'}};
}
formModel: FormGroup;
constructor(fb: FormBuilder) {
this.formModel = fb.group ({
username: ['', [Vaildators.required, Validators.minLength(6)]],
mobile: ['', this.mobileValidator],
passwordsGroup: fb.group({
password: [''],
pconfirm: ['']
}, {validator: this.equalValidator})
});
}
onSubmit() {
// const isValid: boolean = this.formModel.get('username').valid;
// console.log('username的校验结果:' + isValid);
// const errors: any = this.formModel.get("username").errors;
// console.log('username的错误信息是:' + JSON.stringify(errors));
if (this.formModel.valid) {
console.log(this.formModel.value);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 状态字段
touched和untouched
<form [FormGroup]="formModel" (onSubmit)="onSubmit()">
<div>用户名:<input type="text" formControlName="username"></div>
<div [hidden]="formModel.get('mobile').valid || formModel.get('mobile').untouched">
<div [hidden]="!formModel.hasError('required', 'username')">
用户名是必填项
</div>
</div>
...
</form>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
pristine和dirty
<form [FormGroup]="formModel" (onSubmit)="onSubmit()">
<div>用户名:<input type="text" formControlName="username"></div>
<div [hidden]="formModel.get('mobile').valid || formModel.get('mobile').pristine">
<div [hidden]="!formModel.hasError('required', 'username')">
用户名是必填项
</div>
</div>
...
</form>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
pending
<form [FormGroup]="formModel" (onSubmit)="onSubmit()">
<div [hidden]="!formModel.get('mobile').pending">
正在校验手机
</div>
...
</form>
1
2
3
4
5
6
2
3
4
5
6