基于大表单用户选择的验证
Validation based on user selection in large form
我有一个用户表单,其中有多个字段,根据用户的类型,我使用了 angular 反应式表单并想要验证我的字段
这是我的组件 ts 代码:
export class AppComponent implements OnInit {
userformGroup: FormGroup;
Types = [ "user","admin", "guest"];
type: string;
constructor(
private formBuilder: FormBuilder){}
ngOnInit() {
this.userformGroup = this.formBuilder.group({
type: ['user'],
userName : [''],
firstName :[''],
lastName :[''],
email :[''],
contactNumber :[''],
licenseNo :[''],
age:[''],
birthDate :[''],
city:[''],
country:[''],
zipCode :[''],
countryCode:['']
});
}
updateValidators() {
if (this.type === 'user') {
this.userformGroup.get('userName').setValidators([Validators.required]);
this.userformGroup.get('firstName').setValidators([Validators.required]);
this.userformGroup.get('lastName').setValidators([Validators.required]);
this.userformGroup.get('email').setValidators([Validators.required]);
this.userformGroup.get('contactNumber').setValidators([Validators.required]);
this.userformGroup.get('licenseNo').setValidators([Validators.required]);
this.userformGroup.get('age').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('birthDate').setValidators([Validators.required]);
this.userformGroup.get('city').setValidators([Validators.required]);
this.userformGroup.get('country').setValidators([Validators.required]);
this.userformGroup.get('zipCode').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('countryCode').setValidators([Validators.minLength(3)]);
}
else if(this.type === 'admin')
{
this.userformGroup.get('userName').setValidators([Validators.required]);
this.userformGroup.get('firstName').setValidators([Validators.required]);
this.userformGroup.get('lastName').setValidators([Validators.required]);
this.userformGroup.get('email').setValidators([Validators.required]);
this.userformGroup.get('contactNumber').setValidators([]);
this.userformGroup.get('licenseNo').setValidators([Validators.required]);
this.userformGroup.get('age').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('birthDate').setValidators([]);
this.userformGroup.get('city').setValidators([Validators.required]);
this.userformGroup.get('country').setValidators([]);
this.userformGroup.get('zipCode').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('countryCode').setValidators([Validators.minLength(3)]);
}
else if(this.type === 'guest')
{
this.userformGroup.get('userName').setValidators([]);
this.userformGroup.get('firstName').setValidators([]);
this.userformGroup.get('lastName').setValidators([Validators.required]);
this.userformGroup.get('email').setValidators([]);
this.userformGroup.get('contactNumber').setValidators([]);
this.userformGroup.get('licenseNo').setValidators([Validators.required]);
this.userformGroup.get('age').setValidators([]);
this.userformGroup.get('birthDate').setValidators([]);
this.userformGroup.get('city').setValidators([Validators.required]);
this.userformGroup.get('country').setValidators([]);
this.userformGroup.get('zipCode').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('countryCode').setValidators([Validators.minLength(3)]);
}
this.userformGroup.get('userName').updateValueAndValidity();
this.userformGroup.get('firstName').updateValueAndValidity();
this.userformGroup.get('lastName').updateValueAndValidity();
this.userformGroup.get('email').updateValueAndValidity();
this.userformGroup.get('contactNumber').updateValueAndValidity();
this.userformGroup.get('licenseNo').updateValueAndValidity();
this.userformGroup.get('age').updateValueAndValidity();
this.userformGroup.get('birthDate').updateValueAndValidity();
this.userformGroup.get('city').updateValueAndValidity();
this.userformGroup.get('country').updateValueAndValidity();
this.userformGroup.get('zipCode').updateValueAndValidity();
this.userformGroup.get('countryCode').updateValueAndValidity();
}
onChange(event: any) {
this.type = event.target.value;
this.updateValidators();
}
}
这段代码工作正常,但我正在寻找一种优化的验证方法,我该怎么做才能不必在相同的字段上重复应用验证?
您可以重新组织验证条件。
直接将验证应用于所有 3 种类型共有的声明。
this.userformGroup = this.formBuilder.group({
type: ['user'],
userName: [''],
firstName: [''],
lastName: ['', [Validators.required]],
email: [''],
contactNumber: [''],
licenseNo: ['', [Validators.required]],
age: [''],
birthDate: [''],
city: ['', [Validators.required]],
country: [''],
zipCode: ['', [Validators.pattern('/^-?(0|[1-9]\d*)?$/')]],
countryCode: ['', [Validators.required, Validators.minLength(3)]]
});
重组 updateValidators
函数中的 if else
块
if (this.type === 'user' || this.type === 'admin') {
this.userformGroup.get('userName').setValidators([Validators.required]);
this.userformGroup.get('firstName').setValidators([Validators.required]);
this.userformGroup.get('email').setValidators([Validators.required]);
this.userformGroup.get('age').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
} else {
this.userformGroup.get('userName').setValidators([]);
this.userformGroup.get('firstName').setValidators([]);
this.userformGroup.get('email').setValidators([]);
this.userformGroup.get('age').setValidators([]);
}
if (this.type === 'user') {
this.userformGroup.get('contactNumber').setValidators([Validators.required]);
this.userformGroup.get('birthDate').setValidators([Validators.required]);
this.userformGroup.get('country').setValidators([Validators.required]);
}
else {
this.userformGroup.get('contactNumber').setValidators([]);
this.userformGroup.get('birthDate').setValidators([]);
this.userformGroup.get('country').setValidators([]);
}
您无需在验证永远不会更改的控件上调用 updateValueAndValidity
。
我注意到您的代码存在一些其他问题。
onChange
函数永远不会从 html. 调用
updateValidators
表单初始化时未调用函数。在这种情况下,这是必需的,因为您要将 'user' 值分配给类型控件。在表单初始化后添加这两行。
this.type = 'user';
this.updateValidators();
第 12 行 html 有错字,应该是
formControlName="userName"
您可以编写自定义验证器函数,根据当前用户类型应用不同的验证:
requiredForTypes(...types: string[]): ValidatorFn {
return (control: AbstractControl) => {
if (types.indexOf(this.type) > -1) {
return Validators.required(control);
}
return null;
}
}
然后更新您的表单控件以使用自定义验证器:
this.userformGroup = this.formBuilder.group({
type: [this.type, Validators.required],
userName: new FormControl('', this.requiredForTypes('user', 'admin')),
firstName: new FormControl('', this.requiredForTypes('user', 'admin')),
lastName: new FormControl('', Validators.required),
email: new FormControl('', this.requiredForTypes('user', 'admin')),
contactNumber: new FormControl('', this.requiredForTypes('user')),
licenseNo: new FormControl('', Validators.required),
age: new FormControl('', Validators.pattern('/^-?(0|[1-9]\d*)?$/')),
birthDate: new FormControl('', this.requiredForTypes('user')),
city: new FormControl('', Validators.required),
country: new FormControl('', this.requiredForTypes('user')),
zipCode: new FormControl('', Validators.pattern('/^-?(0|[1-9]\d*)?$/')),
countryCode: new FormControl('', Validators.minLength(3)),
});
最后,每当用户类型改变时触发验证:
this.userformGroup.controls.type.valueChanges.subscribe(type => {
this.type = type;
Object.keys(this.userformGroup.controls).forEach(key => {
if (key !== 'type') {
this.userformGroup.controls[key].updateValueAndValidity();
}
})
});
您可以使用条件表达式根据用户的选择使用验证,而不是制作自定义验证函数或在组件中编写太多代码,这里我使用了@rxweb 验证器(RxwebValidators)的验证。
最优代码为:
export class UserInfoAddComponent implements OnInit {
userInfoFormGroup: FormGroup
Types = [ "user","admin", "guest"];
constructor(
private formBuilder: RxFormBuilder
) { }
ngOnInit(){
this.userInfoFormGroup = this.formBuilder.group({
type:[''],
userName :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
firstName :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
lastName :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
email :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
contactNumber :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
licenseNo :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
age:['', RxwebValidators.pattern({expression:{'onlyDigit': /^[0-9]*$/} ,conditionalExpression:(x) => x.type == 'user' })],
birthDate:['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
city:['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
country:['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
zipCode:['',RxwebValidators.pattern({expression:{'zipCode': /^-?(0|[1-9]\d*)?$/} ,conditionalExpression:(x) => x.type == 'user' })],
countryCode:['',RxwebValidators.minLength({value:3,conditionalExpression:(x) => x.type == 'user' })],
});
}
}
Stackblitz 工作示例
我有一个用户表单,其中有多个字段,根据用户的类型,我使用了 angular 反应式表单并想要验证我的字段
这是我的组件 ts 代码:
export class AppComponent implements OnInit {
userformGroup: FormGroup;
Types = [ "user","admin", "guest"];
type: string;
constructor(
private formBuilder: FormBuilder){}
ngOnInit() {
this.userformGroup = this.formBuilder.group({
type: ['user'],
userName : [''],
firstName :[''],
lastName :[''],
email :[''],
contactNumber :[''],
licenseNo :[''],
age:[''],
birthDate :[''],
city:[''],
country:[''],
zipCode :[''],
countryCode:['']
});
}
updateValidators() {
if (this.type === 'user') {
this.userformGroup.get('userName').setValidators([Validators.required]);
this.userformGroup.get('firstName').setValidators([Validators.required]);
this.userformGroup.get('lastName').setValidators([Validators.required]);
this.userformGroup.get('email').setValidators([Validators.required]);
this.userformGroup.get('contactNumber').setValidators([Validators.required]);
this.userformGroup.get('licenseNo').setValidators([Validators.required]);
this.userformGroup.get('age').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('birthDate').setValidators([Validators.required]);
this.userformGroup.get('city').setValidators([Validators.required]);
this.userformGroup.get('country').setValidators([Validators.required]);
this.userformGroup.get('zipCode').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('countryCode').setValidators([Validators.minLength(3)]);
}
else if(this.type === 'admin')
{
this.userformGroup.get('userName').setValidators([Validators.required]);
this.userformGroup.get('firstName').setValidators([Validators.required]);
this.userformGroup.get('lastName').setValidators([Validators.required]);
this.userformGroup.get('email').setValidators([Validators.required]);
this.userformGroup.get('contactNumber').setValidators([]);
this.userformGroup.get('licenseNo').setValidators([Validators.required]);
this.userformGroup.get('age').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('birthDate').setValidators([]);
this.userformGroup.get('city').setValidators([Validators.required]);
this.userformGroup.get('country').setValidators([]);
this.userformGroup.get('zipCode').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('countryCode').setValidators([Validators.minLength(3)]);
}
else if(this.type === 'guest')
{
this.userformGroup.get('userName').setValidators([]);
this.userformGroup.get('firstName').setValidators([]);
this.userformGroup.get('lastName').setValidators([Validators.required]);
this.userformGroup.get('email').setValidators([]);
this.userformGroup.get('contactNumber').setValidators([]);
this.userformGroup.get('licenseNo').setValidators([Validators.required]);
this.userformGroup.get('age').setValidators([]);
this.userformGroup.get('birthDate').setValidators([]);
this.userformGroup.get('city').setValidators([Validators.required]);
this.userformGroup.get('country').setValidators([]);
this.userformGroup.get('zipCode').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]);
this.userformGroup.get('countryCode').setValidators([Validators.minLength(3)]);
}
this.userformGroup.get('userName').updateValueAndValidity();
this.userformGroup.get('firstName').updateValueAndValidity();
this.userformGroup.get('lastName').updateValueAndValidity();
this.userformGroup.get('email').updateValueAndValidity();
this.userformGroup.get('contactNumber').updateValueAndValidity();
this.userformGroup.get('licenseNo').updateValueAndValidity();
this.userformGroup.get('age').updateValueAndValidity();
this.userformGroup.get('birthDate').updateValueAndValidity();
this.userformGroup.get('city').updateValueAndValidity();
this.userformGroup.get('country').updateValueAndValidity();
this.userformGroup.get('zipCode').updateValueAndValidity();
this.userformGroup.get('countryCode').updateValueAndValidity();
}
onChange(event: any) {
this.type = event.target.value;
this.updateValidators();
}
}
这段代码工作正常,但我正在寻找一种优化的验证方法,我该怎么做才能不必在相同的字段上重复应用验证?
您可以重新组织验证条件。
直接将验证应用于所有 3 种类型共有的声明。
this.userformGroup = this.formBuilder.group({ type: ['user'], userName: [''], firstName: [''], lastName: ['', [Validators.required]], email: [''], contactNumber: [''], licenseNo: ['', [Validators.required]], age: [''], birthDate: [''], city: ['', [Validators.required]], country: [''], zipCode: ['', [Validators.pattern('/^-?(0|[1-9]\d*)?$/')]], countryCode: ['', [Validators.required, Validators.minLength(3)]] });
重组
updateValidators
函数中的if else
块if (this.type === 'user' || this.type === 'admin') { this.userformGroup.get('userName').setValidators([Validators.required]); this.userformGroup.get('firstName').setValidators([Validators.required]); this.userformGroup.get('email').setValidators([Validators.required]); this.userformGroup.get('age').setValidators([Validators.pattern('/^-?(0|[1-9]\d*)?$/')]); } else { this.userformGroup.get('userName').setValidators([]); this.userformGroup.get('firstName').setValidators([]); this.userformGroup.get('email').setValidators([]); this.userformGroup.get('age').setValidators([]); } if (this.type === 'user') { this.userformGroup.get('contactNumber').setValidators([Validators.required]); this.userformGroup.get('birthDate').setValidators([Validators.required]); this.userformGroup.get('country').setValidators([Validators.required]); } else { this.userformGroup.get('contactNumber').setValidators([]); this.userformGroup.get('birthDate').setValidators([]); this.userformGroup.get('country').setValidators([]); }
您无需在验证永远不会更改的控件上调用
updateValueAndValidity
。
我注意到您的代码存在一些其他问题。
onChange
函数永远不会从 html. 调用
updateValidators
表单初始化时未调用函数。在这种情况下,这是必需的,因为您要将 'user' 值分配给类型控件。在表单初始化后添加这两行。this.type = 'user'; this.updateValidators();
第 12 行 html 有错字,应该是
formControlName="userName"
您可以编写自定义验证器函数,根据当前用户类型应用不同的验证:
requiredForTypes(...types: string[]): ValidatorFn {
return (control: AbstractControl) => {
if (types.indexOf(this.type) > -1) {
return Validators.required(control);
}
return null;
}
}
然后更新您的表单控件以使用自定义验证器:
this.userformGroup = this.formBuilder.group({
type: [this.type, Validators.required],
userName: new FormControl('', this.requiredForTypes('user', 'admin')),
firstName: new FormControl('', this.requiredForTypes('user', 'admin')),
lastName: new FormControl('', Validators.required),
email: new FormControl('', this.requiredForTypes('user', 'admin')),
contactNumber: new FormControl('', this.requiredForTypes('user')),
licenseNo: new FormControl('', Validators.required),
age: new FormControl('', Validators.pattern('/^-?(0|[1-9]\d*)?$/')),
birthDate: new FormControl('', this.requiredForTypes('user')),
city: new FormControl('', Validators.required),
country: new FormControl('', this.requiredForTypes('user')),
zipCode: new FormControl('', Validators.pattern('/^-?(0|[1-9]\d*)?$/')),
countryCode: new FormControl('', Validators.minLength(3)),
});
最后,每当用户类型改变时触发验证:
this.userformGroup.controls.type.valueChanges.subscribe(type => {
this.type = type;
Object.keys(this.userformGroup.controls).forEach(key => {
if (key !== 'type') {
this.userformGroup.controls[key].updateValueAndValidity();
}
})
});
您可以使用条件表达式根据用户的选择使用验证,而不是制作自定义验证函数或在组件中编写太多代码,这里我使用了@rxweb 验证器(RxwebValidators)的验证。
最优代码为:
export class UserInfoAddComponent implements OnInit {
userInfoFormGroup: FormGroup
Types = [ "user","admin", "guest"];
constructor(
private formBuilder: RxFormBuilder
) { }
ngOnInit(){
this.userInfoFormGroup = this.formBuilder.group({
type:[''],
userName :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
firstName :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
lastName :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
email :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
contactNumber :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
licenseNo :['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
age:['', RxwebValidators.pattern({expression:{'onlyDigit': /^[0-9]*$/} ,conditionalExpression:(x) => x.type == 'user' })],
birthDate:['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
city:['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
country:['',RxwebValidators.required({conditionalExpression:(x) => x.type == 'user' })],
zipCode:['',RxwebValidators.pattern({expression:{'zipCode': /^-?(0|[1-9]\d*)?$/} ,conditionalExpression:(x) => x.type == 'user' })],
countryCode:['',RxwebValidators.minLength({value:3,conditionalExpression:(x) => x.type == 'user' })],
});
}
}
Stackblitz 工作示例