前面angular已经做了2次专题了,今天我们继续学习,来看一下如何在表单中自定义验证控件。
下面是一段很长的html代码,算了我还是一步步来吧。。
1.任何一个表单都会有[formGroup]="userForm"这样的字段,这个表单的获取就是通过‘userForm’
2.formControlName="name" 代表着个input是当前这个表单控件,获取它可以用:userForm.controls.name
有了上面的知识我先把完整的表单html代码拿出来
上面2个表单有2个控件,一个是name,一个是mobile,注意下面这段
有效
// 如果表单name控件值是valid,有效就会显示。
姓名最小长度为3
// 如果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$ = 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就很清楚了。
上面这段代码一看就清楚了是不是,注意的是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$ = 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$ =
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里面引入的
电话号码格式不正确
对应的是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里面都可以引入使用。需要注意的是
电话号码格式不正确
.validateMobile 要和return值的{}里面的保持一致。好了,这期就先到这里。。。