我正在尝试找出在 Angular 中实现跨域验证的最佳方法。
例如,我有一个选择字段,使另一个字段成为必填字段。
我希望能够:
到目前为止,我想出了三种解决方案,但对我来说不太有说服力。
这是一个 Stackblitz 实现,演示了我的调查。
更新 - 另一种方法 看到这个SO
更新 - 更好的方法
在表单上创建
customValidator
并使用验证器将 setError
用于所需的控件。使用 setError
,让 Angular 为我们添加 ng-invalid
,并且我们不需要订阅值更改。参见:
form: FormGroup = new FormGroup(
{
input1: new FormControl('optional'),
input2: new FormControl(null),
},
{ validators: this.customValidatorForm() },
);
customValidatorForm() {
return (form: FormGroup) => {
const error =
form.get('input1').value != 'optional' && !form.get('input2').value
? { required: true }
: null;
form.get('input2').setErrors(error); //<--see the setErrors
return error;
};
}
旧答案
只需使用
customValidator
,例如:
form: FormGroup = new FormGroup({
input1: new FormControl('optional'),
input2: new FormControl(null, this.customValidator()),
});
customValidator() {
return (control: any) => {
if (!control.parent) return null;
let mandatory = control.parent.get('input1').value;
return mandatory != 'optional' && !control.value ? { required: true } : null;
};
}
不要求
control.parent
的另一种选择是使用.bind(this)
。这允许我们在验证器内部访问组件的所有变量,当然还可以访问 this.form
:
form: FormGroup = new FormGroup({
input1: new FormControl('optional'),
input2: new FormControl(null, this.customValidator().bind(this)), //<--bind(this)
});
customValidatorBind() {
return (control: any) => {
if (!this.form) return null;
let mandatory = this.form.get('input1').value;
return mandatory != 'optional' && !control.value ? { required: true } : null;
};
}
好吧,正如我们希望的那样,当更改
input1
input2
被选中时,您需要使用,在创建表单后订阅 valueChanges
:
this.form.get('input1').valueChanges.subscribe(() => {
this.form.get('input2').updateValueAndValidity();
});
对于跨字段验证,您可以使用
required
验证 @rxweb/reactive-form-validation
。
您只需在 formControl 中提及
conditionalExpression
,如下所示:
input2:['', RxwebValidators.required({conditionalExpression:'x => x.input1 == "mandatory"' })]
并像这样在你的app.component.ts中设置错误消息
ngOnInit(){
ReactiveFormConfig.set({"validationMessage":{"required":"This field is required"}});
}
这是完整的组件代码:
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from "@angular/forms"
import { RxwebValidators } from '@rxweb/reactive-form-validators';
@Component({
selector: 'app-required-conditionalExpression-validator',
templateUrl: './required-conditional-expression.component.html'
})
export class RequiredConditionalExpressionValidatorComponent implements OnInit {
userFormGroup: FormGroup
constructor(
private formBuilder: FormBuilder )
{ }
ngOnInit() {
this.userFormGroup = this.formBuilder.group({
input1:[''],
input2:['', RxwebValidators.required({conditionalExpression:'x => x.input1 == "mandatory"' })],
});
}
}
这是您的完整 HTML 代码:
<div>
<form [formGroup]="userFormGroup">
<div>
<label>Mandatory/Optional </label>
<select formControlName="input1">
<option value="optional">Optional</option>
<option value="mandatory">Mandatory</option>
</select>
<br/><br/>
</div>
<div>
<label>Input2</label>
<input type="text" formControlName="input2"/><br/>
<span>
{{userFormGroup.controls.input2.errors?.required?.message}}
</span>
</div>
</form>
</div>
这是工作示例
基于此评论的“更好的方法”:https://stackoverflow.com/a/57123631/8126632
我会以这种方式编辑它,以防止任何其他验证被覆盖:
input2: new FormControl('', [Validators.minLength(4)]),
form.get('input2').setErrors({...error, ...(form.get('input2').errors)});
否则就是一个完美的答案。