我正在使用 Angular Forms 开发一个表单,但我遇到了一个死胡同,我想仅当第一个输入字段不为空时才向第二个输入字段添加验证。
假设我有两个输入字段:姓名和年龄。因此,当在姓名中输入某些内容时,只有年龄才会被设置为必填。我在表单中使用 FormGroup 和 FormControl,这就是组件文件现在的样子,没有年龄验证器:
class Component implements OnChanges {
@Input() name: string;
@Input() age: string;
form = new FormGroup({
name: new FormControl(''),
age: new FormControl('')
});
ngOnChanges(changes) {
if (changes.name?.currentValue !== changes.name?.previousValue) {
this.setName(changes.name.currentValue);
}
if (changes.age?.currentValue !== changes.age?.previousValue) {
this.setAge(changes.age.currentValue);
}
}
setName(name) {
this.form.patchValue({
name,
});
if (name) {
this.form.get('age').setValidators([
Validators.required,
this.form.get('age').validator
]);
}
}
setAge(age) {
this.form.patchValue({
age,
});
}
}
这是模板:
<custom-input
label="Name"
placeholder="name"
name="name"
formControlName="name"
></custom-input>
<custom-input
label="Age"
placeholder="age"
name="age"
formControlName="age"
></custom-input>
您可以使用以下方法!
监听您想要的表单字段的更改事件,然后检查该字段是否已填充,然后我们可以使用命令
setValidators
切换所需的内容,然后在更新后我们可以通过运行updateValueAndValidity
确保表单同步这将重新验证表格!
ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import {
FormBuilder,
FormControl,
FormGroup,
Validators,
} from '@angular/forms';
import { Subscription } from 'rxjs';
import { pairwise, startWith } from 'rxjs/operators';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit, OnDestroy {
name = 'Angular';
form: FormGroup;
subscription: Subscription;
constructor(private formBuilder: FormBuilder) {}
ngOnInit(): void {
this.form = this.formBuilder.group({
control1: [''],
control2: [''],
});
}
control1Change() {
const control1 = <FormControl>this.form.get('control1');
const control2 = <FormControl>this.form.get('control2');
if (control1.value) {
control2.setValidators([Validators.required]);
} else {
control2.setValidators(null);
}
control2.updateValueAndValidity();
}
control2Change() {
const control1 = <FormControl>this.form.get('control1');
const control2 = <FormControl>this.form.get('control2');
if (control2.value) {
control1.setValidators([Validators.required]);
} else {
control1.setValidators(null);
}
control1.updateValueAndValidity();
}
ngOnDestroy(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}
HTML
<hello name="{{ name }}"></hello>
<form [formGroup]="form">
<div style="margin-bottom: 1rem">
<label for="control1">Make Field 2 required</label>
<input
id="control1"
type="text"
formControlName="control1"
(change)="control1Change()"
/>
<span
*ngIf="form.controls.control1.hasError('required')"
style="color: red; display: block; margin-top: 0.25rem;"
>Field 2 is required</span
>
</div>
<div style="margin-bottom: 1rem">
<label for="control2"> Field 2 </label>
<input
id="control2"
type="text"
formControlName="control2"
(change)="control2Change()"
/>
<span
*ngIf="form.controls.control2.hasError('required')"
style="color: red; display: block; margin-top: 0.25rem;"
>Field 2 is required</span
>
</div>
<div>
<button type="submit" [disabled]="!form.valid">
Only enabled when form is valid
</button>
</div>
</form>
我有同样的需求,这是我基于自定义验证器的解决方案。
在这种情况下,如果
formControlA
的值不为空,则需要 formControlB
。
这是我的自定义验证器:
/**
* Generates a validator function that checks if a reference control is not null.
*
* @param {string} referenceControlName - The name of the control in the same form group that holds the reference value.
* @return {ValidatorFn} A validator function
*/
export function RequiredIfControlIsNotNullValidator(referenceControlName: string): ValidatorFn {
return (currentControl: AbstractControl): { [key: string]: any } => {
// Get the reference control from the parent formGroup
const referenceControl = currentControl.parent ? currentControl.parent.get(referenceControlName) : null;
// Throw an error if the reference control is null or undefined
if (referenceControl == null)
throw Error("Reference formControl is null or undefined");
// Check if the reference control value is null or undefined
const refValueIsNullOrUndefined = referenceControl.value == null || referenceControl.value == undefined;
// Return the validation result
return refValueIsNullOrUndefined ? null : { [`${referenceControlName}IsNotNull`]: true };
};
}
在您的组件中,以这种方式将其分配给您的 formControl :
this.myForm = new FormGroup({
formControlA: new FormControl<string | null>({ value: null, disabled: false }, [Validators.nullValidator]),
formControlB: new FormControl<string | null>({ value: null, disabled: false }, [RequiredIfControlIsNotNullValidator('formControlA')])
});
但是,每次
formControlB
的值更新时,我们都需要运行 formControlA
的验证。因此,在组件的 ngOnInit 中,对 formControlA
的 valueChanges 做出反应
public ngOnInit(): void {
// [...]
this.myForm.get("formControlA").valueChanges.subscribe(vc => {
this.visitForm.get('formControlB').updateValueAndValidity();
});
// [...]
}
然后,验证器会生成一个自定义错误密钥,因此您可以使用它在模板中显示适当的错误消息
<form [formGroup]="myForm">
<div>
<input formControlName="formControlA" />
</div>
<div>
<input formControlName="formControlB" />
<span class="error" *ngIf="myForm.get('formControlB').hasError('formControlAIsNotNull')">
The value of A is not null, hence B is required
</span>
</div>
</form>