The demo address of this article: source code or final effect
In the project, we sometimes need to move the validation of the form to do dynamic planning. For example, two kinds of users are registered simultaneously in one registration interface, but the input items of the two kinds of users are not the same.
If you are a teacher, you are required to enter a job number:
If you are a student user, you are required to enter the student ID:
We call this scenario dynamic form validation.
In the validation of the above table, we require:
- Work number and student number do not interfere with each other.
- When selecting a teacher type, it is only judged whether the job number has been entered.
- When selecting a student type, it is only judged whether the student number has been entered.
Implementation plan
In fact, there are many ways to implement this. There are roughly three types of the ones we've used in the project:
- Use cross-field validators.
- Subscribe to the user type and reset the verification rules for the
worker ID or
student ID when the user type is changed.
- Subscribe to the user type, when the user type is changed, add or remove the
fromGroup
ID,
student ID FromControl in 0623483c8a199d.
Cross field validator
Anguar's official gives an example of using a cross-field validator in , the idea is to add a validator to FromGroup
, and then get the value of FormControl
in the validator, and verify it according to the specific situation.
advantage:
- Official example, low learning cost.
- The verification is directly put into the validator, and the logic is clear.
- The validator has no effect on getting the value of
FromGroup
.
shortcoming:
- It is not possible to define validation conditions directly in
FormControl
, which is not intuitive. - Only error messages can be displayed uniformly, and error messages cannot be customized for a single field.
You can click https://segmentfault.com/a/1190000041563611 to see the implementation example.
reset validation rules
FromControl
provides clearValidators()
to clear the validator, and setValidators()
to set the validator, so we can subscribe whether the user type changes, when the change occurs, clear the validator of the cross field according to the situation, and then re-set its validator.
advantage:
- Provides a new idea for dynamically adding asynchronous validators
shortcoming:
- Validation rules are not intuitive.
- A lot of code.
Reset FromGroup items
FromGroup
provided by removeControl()
allows us to remove the FormControl
in it. Using this mechanism, we can remove and add the corresponding FormControl
according to the situation after the subscription user type changes, so as to achieve the purpose of dynamically validating the form.
Example code C layer:
export class AppComponent implements OnInit {
name = 'Angular ' + VERSION.major;
formGroup = new FormGroup({});
// 学号
studentNoFormControl = new FormControl(null, Validators.required);
// 工号
teachterNoFormControl = new FormControl(null, Validators.required);
// 用户类型
typeFormControl = new FormControl(null, Validators.required);
ngOnInit(): void {
this.formGroup.addControl('name', new FormControl('', Validators.required));
this.formGroup.addControl('type', this.typeFormControl);
// 订阅类型的变化,从而决定在formGroup中添加学号还是工号FormControl
this.typeFormControl.valueChanges.subscribe((type) => {
if (type === 0) {
this.formGroup.removeControl('studentNo');
this.formGroup.addControl('teacherNo', this.teachterNoFormControl);
} else {
this.formGroup.removeControl('teacherNo');
this.formGroup.addControl('studentNo', this.studentNoFormControl);
}
});
// 初始化用户类型为教师
this.typeFormControl.setValue(0);
}
onSubmit(): void {
alert('submit');
}
/**
* 显示学号或是工号的input
*/
showStudent(): boolean {
return this.typeFormControl.value === 1;
}
}
Layer V:
<hello name="{{ name }}"></hello>
<p>表单动态验证示例</p>
<pre>{{ formGroup.invalid | json }}</pre>
<pre>{{ formGroup.get('type').value | json }}</pre>
<form [formGroup]="formGroup">
<div>姓名:<input type="text" formControlName="name" /></div>
<div>
用户类型:
<label
><input type="radio" [value]="0" formControlName="type" name="type" />
教师</label
>
<label
><input type="radio" [value]="1" formControlName="type" name="type" />
学生</label
>
</div>
<div *ngIf="showStudent()">
学号:<input type="text" formControlName="studentNo" />
</div>
<div *ngIf="!showStudent()">
工号:<input type="text" formControlName="teacherNo" />
</div>
<button [disabled]="formGroup.invalid" (click)="onSubmit()">Submit</button>
</form>
advantage:
- Set the validator directly on
FormControl
, the code is intuitive. - You can directly use the class attributes such as ngvalid provided by angular to quickly define the style of the validation result.
shortcoming:
- The validator has an effect on getting the value of
FromGroup
. For example, in the subsequent operation to obtain the relevant value ofFormGroup
, it is necessary to judge whetherFormGroup
has a value, which may easily cause the error of callingundefined
onvalue
. (This can be circumvented using?
----formGroup.get('xxx')?.value
.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。