Abstract
Angular提供了两种方式来进行表单管理,reactive表单和template-driven表单。后面简称为响应式表单,模板驱动表单。
响应式表单
提供对底层表单对象模型的直接,显示访问。与模板驱动表单相比,它们更加健壮:它们具有可伸缩性、可重用性和可测试性。如果表单是应用程序的关键部分,或者你已经在使用响应式模式构建应用程序,那么就应该使用响应式表单。
模板驱动表单
依赖模板中的指令来创建和操作底层对象模型。它们对于在应用程序中添加简单的表单很有用,比如电子邮件列表注册表单。它们可以直接添加到应用程序中,但它们不像响应式表单那样可扩展。如果您有非常基本的表单需求和逻辑,可以在模板中单独管理,那么模板驱动表单可能是一个很好的选择。
响应式表单详解
管理单个表单项-FormControl
demo.commponent.ts:
public colorControl = new FormControl('123');
demo.component.html:
<p>demo works!</p>
<label for="color">Color: </label>
<input id="color" type="text" [formControl]="colorControl" />
效果:
管理一组表单项-FormGroup
html:
<form [formGroup]="form">
<label for="name">姓名: </label>
<input id="name" formControlName="name" />
<div *ngIf="form.get('name')?.errors" class="alert">请输入姓名!</div>
<br />
<label for="tel">电话: </label>
<input formControlName="tel" id="tel" />
<div *ngIf="form.get('tel')?.errors?.['minlength']" class="alert">电话号码长度不得小于11!</div>
<div *ngIf="form.get('tel')?.errors?.['maxlength']" class="alert">电话号码长度不得超过11!</div>
</form>
css:
.ng-invalid:not(form){
border: 2px solid #a94442;
}
.alert{
color: #820000;
}
ts:
import { FormControl, FormGroup, Validators } from '@angular/forms';
public form = new FormGroup({
name: new FormControl('', Validators.required),
tel: new FormControl('xxx-01234567', [
Validators.minLength(11),
Validators.maxLength(11),
]),
});
效果:
表单校验-Built-in校验器
追加html:
<section>
<button (click)="submit()">提交</button>
</section>
追加ts:
public submit() {
console.log(this.form);
if (this.form.invalid) {
alert('表单校验失败!');
return;
}
console.log('submit!', this.form.value);
}
效果:
表单校验-自定义校验器
html:
<form [formGroup]="form">
<label for="name">姓名: </label>
<input id="name" formControlName="name" />
<div *ngIf="form.get('name')?.errors" class="alert">请输入姓名!</div>
<br />
<label for="tel">电话: </label>
<input formControlName="tel" id="tel" />
<div *ngIf="form.get('tel')?.errors?.['length']" class="alert">电话号码长度必须是11位!</div>
</form>
<section>
<button (click)="submit()">提交</button>
</section>
ts:
import {
FormControl,
FormGroup,
Validators,
AbstractControl,
ValidationErrors,
} from '@angular/forms';
public telCustomValidator = (
control: AbstractControl
): ValidationErrors | null => {
const tel = control.value;
if (!tel) {
return { required: true };
}
if (tel.length !== 11) {
return { length: true };
}
return null;
};
public form = new FormGroup({
name: new FormControl('', Validators.required),
tel: new FormControl('xxx-01234567', [this.telCustomValidator]),
});
public submit() {
console.log(this.form);
if (this.form.invalid) {
alert('表单校验失败!');
return;
}
console.log('submit!', this.form.value);
}
效果:
表单校验-自定义交叉校验器
html:
<form [formGroup]="pwdForm">
<label for="pwd">密码: </label>
<input id="pwd" formControlName="pwd" />
<div *ngIf="pwdForm.get('pwd')?.errors" class="alert">请输入密码!</div>
<br />
<label for="confirmPwd">确认密码: </label>
<input formControlName="confirmPwd" id="confirmPwd" />
<div
*ngIf="pwdForm.get('confirmPwd')?.dirty && pwdForm.errors?.['not-confirm']"
class="alert"
>
两次密码输入不一致!
</div>
</form>
ts:
private confirmPwdValidator = (
control: AbstractControl
): ValidationErrors | null => {
const pwd = control.get('pwd')?.value;
const confirmPwd = control.get('confirmPwd')?.value;
if (pwd !== confirmPwd) {
return { 'not-confirm': true };
}
return null;
};
public pwdForm = new FormGroup(
{
pwd: new FormControl('', Validators.required),
confirmPwd: new FormControl('', Validators.required),
},
{ validators: this.confirmPwdValidator }
);
效果:
Tip: 普通自定义校验器的入参control是一个FormControl对象,交叉验证器中它则是一个FormGroup对象。
表单校验-异步校验器
html:
<form [formGroup]="pwdForm">
<label for="pwd">密码: </label>
<input id="pwd" formControlName="pwd" />
<div *ngIf="pwdForm.get('pwd')?.errors?.['required']" class="alert">
请输入密码!
</div>
<div *ngIf="pwdForm.get('pwd')?.errors?.['remote']" class="alert">
{{pwdForm.get('pwd')?.errors?.['remote']}}
</div>
<br />
<label for="confirmPwd">确认密码: </label>
<input formControlName="confirmPwd" id="confirmPwd" />
<div
*ngIf="pwdForm.get('confirmPwd')?.dirty && pwdForm.errors?.['not-confirm']"
class="alert"
>
两次密码输入不一致!
</div>
</form>
ts:
import {
FormControl,
FormGroup,
Validators,
AbstractControl,
ValidationErrors,
} from '@angular/forms';
import { Observable, catchError, map, of } from 'rxjs';
import { checkPwdFn } from 'src/app/request';
private cunstomValidatePwd = (control: AbstractControl):Observable<ValidationErrors | null> => {
return checkPwdFn(control.value).pipe(
map(res=>{
if(res === 'pass'){
// 通过远程校验
return null;
}
return {remote: res}
}),
catchError(()=>of({remote: 'Network error 密码校验失败!'}))
)
}
private confirmPwdValidator = (
control: AbstractControl
): ValidationErrors | null => {
const pwd = control.get('pwd')?.value;
const confirmPwd = control.get('confirmPwd')?.value;
if (pwd !== confirmPwd) {
return { 'not-confirm': true };
}
return null;
};
public pwdForm = new FormGroup(
{
pwd: new FormControl('', {asyncValidators: [this.cunstomValidatePwd],validators: [Validators.required], updateOn :'blur', }),
confirmPwd: new FormControl('', Validators.required),
},
{ validators: this.confirmPwdValidator }
);
效果:
想要源码的,可以来fork我的代码仓:
https://gitee.com/gao-hui007/my-blogs/blob/master/docs/angular/%E8%A1%A8%E5%8D%95.md#
转载请备注来源