Angular 依赖于其他表单控件的表单控件验证器
Angular formControl validators that depend on other formcontrols
我需要创建一个包含 2 个日期的表单,dateFrom 和 dateTo。
验证条件是dateFrom不能在dateTo之后,dateTo不能在dateFrom之前。
所以我创建了一个表单组,其中包含两个表单控件和一个共同的验证器,用于检查此条件。
export class DateRangeSelector {
dateForm: FormGroup = new FormGroup({
dateFrom: new FormControl({ year: 2017, month: 10 },[this.dateValidator.bind(this)]),
dateTo: new FormControl({ year: 2020, month: 11 }, [this.dateValidator.bind(this)])
});
dateValidator(control: FormControl): { [s: string]: boolean } {
const valueDateFrom = this.dateForm.get('dateForm').value;
const valueDateTo = this.dateForm.get('dateTo').value;
if (valueDateFrom && valueDateTo) {
//please ignore the fact that value is {year: x, month: y}, I need to parse
const dateFrom = moment(valueDateFrom);
const dateTo = moment(valueDateTo);
if (dateFrom.isAfter(dateTo)) {
return { invalidDate: true };
}
}
return null;
}
}
我的问题是当验证器尝试验证时,this.dateForm 未定义(不在上下文中)。我不明白,因为我 绑定了 验证器声明 中的方法。
您可以将控件定义为
new FormGroup({
dateFrom: new FormControl('', [validateStartResult]),
dateTo: new FormControl('', [validateEndResult]),
})
然后创建单独的文件进行验证
import {AbstractControl, ValidationErrors, ValidatorFn} from "@angular/forms";
enum ValidationFor {
end = 'end',
start = 'start'
}
export const validateEndResult: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
return validateResult(control, ValidationFor.end);
}
export const validateStartResult: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
return validateResult(control, ValidationFor.start);
}
function validateResult(control, currentValidation: ValidationFor): ValidationErrors | null {
const startControl = control?.root?.get('dateFrom');
const endControl = control?.root?.get('dateTo');
const currentTime = new Date().getTime();
const startTimeStamp = new Date(startControl?.value).getTime(); // configurations yours date
const endTimeStamp = new Date(endControl?.value).getTime(); // configurations yours date
const error: { [key: string]: boolean } = {};
let hasError = false;
if (startTimeStamp > endTimeStamp) { // main codition
if (currentValidation === ValidationFor.end) {
error.endResult = true
}
if (currentValidation === ValidationFor.start) {
error.startResult = true
}
hasError = true;
}
return hasError ? error : null;
}
您可以按照本指南完成自己的验证
检查 formGroup 验证器后:
日期表单:表单组;
dateForm: FormGroup;
constructor(formBuilder: FormBuilder, private toastService: ToastService) {
this.dateForm = formBuilder.group({
dateFrom: { year: 2017, month: 10 },
dateTo: { year: 2018, month: 11 }
});
this.dateForm.setValidators(this.dateValidator());
}
dateValidator(): ValidatorFn {
return (group: FormGroup): ValidationErrors => {
const controlDateFrom = group.controls.dateFrom;
const controlDateTo = group.controls.dateTo;
if (controlDateFrom.value && controlDateTo.value) {
const dateFrom = moment(controlDateFrom.value);
const dateTo = moment(controlDateTo.value);
if (dateFrom.isAfter(dateTo)) {
controlDateFrom.setErrors({ invalidDateRange: true});
controlDateFrom.setErrors({ invalidDateRange: true});
}else{
controlDateFrom.setErrors(null);
controlDateTo.setErrors(null);
}
}
return;
};
}
这个解决方案特别有趣,因为它绑定到组件,例如,当日期错误时,我可以举个例子。或者我可以在设置日期值之前对其进行格式化,这样可以避免所有错误。
我认为 this.dateForm
未定义的原因是因为 Validatdor 在创建单个表单控件本身时被执行,即当 属性 dateForm
仍在创建时。
您可以在现有代码的验证器中执行此操作来验证这一点。
dateValidator() {
console.log(this.dateForm);
}
您会看到该组在两个 undefined
之后打印出来
处理此问题的一个好方法是使用组验证器,例如:
dateForm: FormGroup = new FormGroup(
{
dateFrom: new FormControl({ year: 2017, month: 10 }),
dateTo: new FormControl({ year: 2020, month: 11 }),
},
this.dateValidator.bind(this)
);
dateValidator(group: FormGroup) {
const valueDateFrom = group.get('dateFrom').value;
const valueDateTo = group.get('dateTo').value;
if (valueDateFrom && valueDateTo) {
//please ignore the fact that value is {year: x, month: y}, I need to parse
const dateFrom = new Date(valueDateFrom).getTime(); // moment(valueDateFrom)
const dateTo = new Date(valueDateTo).getTime(); // moment(valueDateTo);
if (dateFrom > dateTo) {
console.log('Error =====> ');
return { invalidDate: true };
}
}
console.log('Success =====> ');
return null;
}
我需要创建一个包含 2 个日期的表单,dateFrom 和 dateTo。 验证条件是dateFrom不能在dateTo之后,dateTo不能在dateFrom之前。
所以我创建了一个表单组,其中包含两个表单控件和一个共同的验证器,用于检查此条件。
export class DateRangeSelector {
dateForm: FormGroup = new FormGroup({
dateFrom: new FormControl({ year: 2017, month: 10 },[this.dateValidator.bind(this)]),
dateTo: new FormControl({ year: 2020, month: 11 }, [this.dateValidator.bind(this)])
});
dateValidator(control: FormControl): { [s: string]: boolean } {
const valueDateFrom = this.dateForm.get('dateForm').value;
const valueDateTo = this.dateForm.get('dateTo').value;
if (valueDateFrom && valueDateTo) {
//please ignore the fact that value is {year: x, month: y}, I need to parse
const dateFrom = moment(valueDateFrom);
const dateTo = moment(valueDateTo);
if (dateFrom.isAfter(dateTo)) {
return { invalidDate: true };
}
}
return null;
}
}
我的问题是当验证器尝试验证时,this.dateForm 未定义(不在上下文中)。我不明白,因为我 绑定了 验证器声明 中的方法。
您可以将控件定义为
new FormGroup({
dateFrom: new FormControl('', [validateStartResult]),
dateTo: new FormControl('', [validateEndResult]),
})
然后创建单独的文件进行验证
import {AbstractControl, ValidationErrors, ValidatorFn} from "@angular/forms";
enum ValidationFor {
end = 'end',
start = 'start'
}
export const validateEndResult: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
return validateResult(control, ValidationFor.end);
}
export const validateStartResult: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
return validateResult(control, ValidationFor.start);
}
function validateResult(control, currentValidation: ValidationFor): ValidationErrors | null {
const startControl = control?.root?.get('dateFrom');
const endControl = control?.root?.get('dateTo');
const currentTime = new Date().getTime();
const startTimeStamp = new Date(startControl?.value).getTime(); // configurations yours date
const endTimeStamp = new Date(endControl?.value).getTime(); // configurations yours date
const error: { [key: string]: boolean } = {};
let hasError = false;
if (startTimeStamp > endTimeStamp) { // main codition
if (currentValidation === ValidationFor.end) {
error.endResult = true
}
if (currentValidation === ValidationFor.start) {
error.startResult = true
}
hasError = true;
}
return hasError ? error : null;
}
您可以按照本指南完成自己的验证
检查 formGroup 验证器后:
日期表单:表单组;
dateForm: FormGroup;
constructor(formBuilder: FormBuilder, private toastService: ToastService) {
this.dateForm = formBuilder.group({
dateFrom: { year: 2017, month: 10 },
dateTo: { year: 2018, month: 11 }
});
this.dateForm.setValidators(this.dateValidator());
}
dateValidator(): ValidatorFn {
return (group: FormGroup): ValidationErrors => {
const controlDateFrom = group.controls.dateFrom;
const controlDateTo = group.controls.dateTo;
if (controlDateFrom.value && controlDateTo.value) {
const dateFrom = moment(controlDateFrom.value);
const dateTo = moment(controlDateTo.value);
if (dateFrom.isAfter(dateTo)) {
controlDateFrom.setErrors({ invalidDateRange: true});
controlDateFrom.setErrors({ invalidDateRange: true});
}else{
controlDateFrom.setErrors(null);
controlDateTo.setErrors(null);
}
}
return;
};
}
这个解决方案特别有趣,因为它绑定到组件,例如,当日期错误时,我可以举个例子。或者我可以在设置日期值之前对其进行格式化,这样可以避免所有错误。
我认为 this.dateForm
未定义的原因是因为 Validatdor 在创建单个表单控件本身时被执行,即当 属性 dateForm
仍在创建时。
您可以在现有代码的验证器中执行此操作来验证这一点。
dateValidator() {
console.log(this.dateForm);
}
您会看到该组在两个 undefined
处理此问题的一个好方法是使用组验证器,例如:
dateForm: FormGroup = new FormGroup(
{
dateFrom: new FormControl({ year: 2017, month: 10 }),
dateTo: new FormControl({ year: 2020, month: 11 }),
},
this.dateValidator.bind(this)
);
dateValidator(group: FormGroup) {
const valueDateFrom = group.get('dateFrom').value;
const valueDateTo = group.get('dateTo').value;
if (valueDateFrom && valueDateTo) {
//please ignore the fact that value is {year: x, month: y}, I need to parse
const dateFrom = new Date(valueDateFrom).getTime(); // moment(valueDateFrom)
const dateTo = new Date(valueDateTo).getTime(); // moment(valueDateTo);
if (dateFrom > dateTo) {
console.log('Error =====> ');
return { invalidDate: true };
}
}
console.log('Success =====> ');
return null;
}