前面angular已经做了2次专题了,今天我们继续学习,来看一下如何在表单中自定义验证控件。
下面是一段很长的html代码,算了我还是一步步来吧。。
<form class="form-horizontal" [formGroup]="userForm" (ngSubmit)="logForm()">
<div class="form-group">
<button class="btn btn-default pull-right" (click)="reset()">重置</button>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">姓名:</label>
<div class="col-sm-10">
<input class="form-control" type="text" formControlName="name">
<span *ngIf="userForm.controls.name.pristine" class="label label-primary">未修改</span>
<span *ngIf="userForm.controls.name.dirty" class="label label-warning">已修改</span>
<span *ngIf="userForm.controls.name.valid" class="label label-success">有效</span>
<div [hidden]="userForm.controls.name.valid || userForm.controls.name.pristine" class="alert alert-danger">
<p *ngIf="userForm.controls.name.errors?.minlength">姓名最小长度为3</p>
<p *ngIf="userForm.controls.name.errors?.required">必须输入姓名</p>
</div>
</div>
</div>
</form>
1.任何一个表单都会有[formGroup]="userForm"这样的字段,这个表单的获取就是通过‘userForm’
2.formControlName="name" 代表着个input是当前这个表单控件,获取它可以用:userForm.controls.name
有了上面的知识我先把完整的表单html代码拿出来
<form class="form-horizontal" [formGroup]="userForm" (ngSubmit)="logForm()">
<div class="form-group">
<button class="btn btn-default pull-right" (click)="reset()">重置</button>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">姓名:</label>
<div class="col-sm-10">
<input class="form-control" type="text" formControlName="name">
<span *ngIf="userForm.controls.name.pristine" class="label label-primary">未修改</span>
<span *ngIf="userForm.controls.name.dirty" class="label label-warning">已修改</span>
<span *ngIf="userForm.controls.name.valid" class="label label-success">有效</span>
<div [hidden]="userForm.controls.name.valid || userForm.controls.name.pristine" class="alert alert-danger">
<p *ngIf="userForm.controls.name.errors?.minlength">姓名最小长度为3</p>
<p *ngIf="userForm.controls.name.errors?.required">必须输入姓名</p>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">电话:</label>
<div class="col-sm-10">
<input class="form-control" type="text" formControlName="mobile">
<span *ngIf="userForm.controls.mobile.pristine" class="label label-primary">未修改</span>
<span *ngIf="userForm.controls.mobile.dirty" class="label label-warning">已修改</span>
<span *ngIf="userForm.controls.mobile.valid" class="label label-success">有效</span>
<div [hidden]="userForm.controls.mobile.valid || userForm.controls.mobile.pristine" class="alert alert-danger">
<p *ngIf="userForm.controls.mobile.errors?.minlength || userForm.controls.mobile.errors?.maxlength">电话长度必须为11</p>
<p *ngIf="userForm.controls.mobile.errors?.required">必须输入电话</p>
<p *ngIf="userForm.controls.mobile.errors?.validateMobile">电话号码格式不正确</p>
</div>
</div>
</div>
</form>
上面2个表单有2个控件,一个是name,一个是mobile,注意下面这段
<span *ngIf="userForm.controls.name.valid" class="label label-success">有效</span>
// 如果表单name控件值是valid,有效就会显示。
<p *ngIf="userForm.controls.name.errors?.minlength">姓名最小长度为3</p>
// 如果name长度小于minlength(3),会显示最小长度错误。
我们来看一下最重要的component.js是如何写的把,先看一下ngOninit如何初始化表单的
ngOnInit() {
this.userForm = this.formBuilder.group({
name: ['张三', [Validators.required, Validators.minLength(3)]],
mobile: [13800138001, [Validators.required, Validators.minLength(11), Validators.maxLength(11), validateMobile]],
address: this.formBuilder.group({
city: ['北京', Validators.required],
street: ['朝阳望京...', Validators.required]
})
});
const addr$ = <FormGroup>this.userForm.controls['address'];
const city$ = addr$.controls['city'];
const street$ = addr$.controls['street'];
city$.valueChanges.debounceTime(1000).distinctUntilChanged().subscribe(cityValue => {
this.msg = cityValue + ' 欢迎你!';
street$.setValue(cityValue);
});
this.userForm.valueChanges.subscribe(x => this.changeMsg = { event: 'Form DATA CHANGED', object: x });
}
我们下面来看一下formBuilder是干嘛的
this.userForm = this.formBuilder.group({
name: ['张三', [Validators.required, Validators.minLength(3)]],
mobile: [13800138001, [Validators.required, Validators.minLength(11), Validators.maxLength(11), validateMobile]],
address: this.formBuilder.group({
city: ['北京', Validators.required],
street: ['朝阳望京...', Validators.required]
})
});
创建了3个表单控件:name mobile address,其中name的默认值是‘张三’,验证规则是[Validators.required, Validators.minLength(3)]
mobile也有验证规则,但是多了一个我们看不懂的validateMobile,等下再说,这就是我们自定义的验证指令。
可以看出来address下面有子控件city street ,那么我们来看这段html就很清楚了。
<fieldset formGroupName="address">
<div class="form-group">
<label class="col-sm-2 control-label">城市:</label>
<div class="col-sm-10">
<input class="form-control" type="text" formControlName="city">
<div [hidden]="userForm.controls.address.controls.city.valid || userForm.controls.address.controls.city.pristine" class="alert alert-danger">
<p *ngIf="userForm.controls.address.controls.city.errors?.required">必须输入城市</p>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">街道:</label>
<div class="col-sm-10">
<input class="form-control" type="text" formControlName="street">
</div>
</div>
</fieldset>
上面这段代码一看就清楚了是不是,注意的是formBuilder的用法,如何创建表单控件。我们来看一下完整的ts文件把
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';
import { validateMobile } from '../validators/mobile.validator';
@Component({
selector: 'reactive-form',
templateUrl: 'app/reactive-forms/reactive-forms.component.html',
styleUrls: ['app/reactive-forms/reactive-forms.component.css']
})
export class ReactiveFormsComponent implements OnInit {
userForm: FormGroup;
msg: String;
changeMsg: any;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.userForm = this.formBuilder.group({
name: ['张三', [Validators.required, Validators.minLength(3)]],
mobile: [13800138001, [Validators.required, Validators.minLength(11), Validators.maxLength(11), validateMobile]],
address: this.formBuilder.group({
city: ['北京', Validators.required],
street: ['朝阳望京...', Validators.required]
})
});
const addr$ = <FormGroup>this.userForm.controls['address'];
const city$ = addr$.controls['city'];
const street$ = addr$.controls['street'];
city$.valueChanges.debounceTime(1000).distinctUntilChanged().subscribe(cityValue => {
this.msg = cityValue + ' 欢迎你!';
street$.setValue(cityValue + ' 欢迎你!');
});
this.userForm.valueChanges.subscribe(x => this.changeMsg = { event: 'Form DATA CHANGED', object: x });
}
logForm(NgForm) {
if (this.userForm.invalid) {
this.msg = 'validation errors!';
} else {
this.msg = null;
}
console.log(this.userForm.value);
}
reset() {
this.userForm.reset();
}
}
从上得出:
-
表单必备引入的:formGroup formBuilder formControl Validators formGroup是表单的入口之处,formBuilder用于创建表单控件结构,formControl用于获取控件,validators是表单验证所需。
-
const addr$ = <FormGroup>this.userForm.controls['address']; 对于这种带有子控件的控件需要用formGroup强转。 比如我们想获得name控件的值,就是this.userForm.controls['name'].value.
我们来看下这2段代码
city$.valueChanges.debounceTime(1000).distinctUntilChanged().subscribe(cityValue => {
this.msg = cityValue + ' 欢迎你!';
street$.setValue(cityValue + ' 欢迎你!');
});
// 监听city控件输入值的改变,有1000ms延迟,同时street$.setValue(cityValue + ' 欢迎你!'); 就是street控件的值也会跟着改变。
this.userForm.valueChanges.subscribe(x => this.changeMsg = { event: 'Form DATA CHANGED', object: x });
// 监控表单的变化,并作出反应,x是表单序列化后的值
其实我们一直想知道的是 mobile: [13800138001, [Validators.required, Validators.minLength(11), Validators.maxLength(11), validateMobile]]里面的这个validateMobile到底是啥。
import { FormControl, NG_VALIDATORS } from '@angular/forms';
import { Directive } from '@angular/core';
// 这不正好是校验电话的正则吗
export function validateMobile(c: FormControl) {
let MOBILE_REGEXP = /^1[0-9]{10}$/;
return MOBILE_REGEXP.test(c.value) ? null : {
validateMobile: {valid: false}
}
}
// 注意导出的validateMobile需要放在providers里面
@Directive({
selector: '[validateMobile]',
providers: [
{ provide: NG_VALIDATORS, useValue: validateMobile, multi: true }
]
})
export class MobileValidator {}
// 这个暴露的MobileValidator需要在app.module里引入
import { validateMobile } from '../validators/mobile.validator'; 这是我们在ts里面引入的
<p *ngIf="userForm.controls.mobile.errors?.validateMobile">电话号码格式不正确</p>
对应的是function validateMobile 后面的 validateMobile
注意需要在app.module中引入MobileValidator
@NgModule({
imports: [BrowserModule, FormsModule, ReactiveFormsModule, RouterModule.forRoot(routes)],
declarations: [AppComponent, TemplateFormsComponent, ReactiveFormsComponent, MobileValidator], // MobileValidator必须引入
bootstrap: [AppComponent]
})
其实我们可以在MobileValidator定义多个验证函数
import { FormControl, NG_VALIDATORS } from '@angular/forms';
import { Directive } from '@angular/core';
export function validateMobile1(c: FormControl) {
let MOBILE_REGEXP = /^1[0-9]{13}$/;
return MOBILE_REGEXP.test(c.value) ? null : {
validateMobile1: {valid: false}
}
}
export function validateMobile2(c: FormControl) {
let MOBILE_REGEXP = /^1[0-5]{5}[0-9]{5}$/;
return MOBILE_REGEXP.test(c.value) ? null : {
validateMobile2: {valid: false}
}
}
@Directive({
selector: '[validateMobile]', // 其实这个名字可以随便取
providers: [
{ provide: NG_VALIDATORS, useValue: validateMobile1, multi: true },
{ provide: NG_VALIDATORS, useValue: validateMobile2, multi: true }
]
})
export class MobileValidator {}
如上上面定义了2个mobile验证规则,在component里面都可以引入使用。需要注意的是
<p *ngIf="userForm.controls.mobile.errors?.validateMobile">电话号码格式不正确</p>
.validateMobile 要和return值的{}里面的保持一致。好了,这期就先到这里。。。
网友评论