跨字段验证在 Angular 中不起作用
Cross field validation doesn't work in Angular
我在两个单独的组件中有两个日期字段。我在生效日期设置验证以验证生效日期是否早于申请日期。如果早于申请日期,将显示错误消息。
我现在的问题是:如果用户先输入申请日期,然后再输入生效日期,则验证工作正常。但是,如果用户在输入生效日期后更改申请日期,则不会触发验证。换句话说,验证仅在生效日期更改时触发。
当申请日期更改时,如何在生效日期触发验证?我还注意到,当 effectiveDate 早于申请日期时,会显示错误消息。然后我将申请日期更改为有效日期,错误消息不会消失。
我尝试将申请日期传递给 effectiveDate 组件。然而,它并没有像我预期的那样工作。
step1.component.html是调用两个组件的页面。我将 applicationDate$ 作为 [minEffectiveDate]="applicationDate$ | async".
传递给子组件
step1.component.html,申请日期在app-internal-use组件里面
<app-internal-use formControlName="internalUse" (brokerSearchIDResult)="addBrokerToApp($event)"
(clientSearchIDResult)="handleClientSearchResult($event)" [shouldShowBrokerSearch]="shouldShowCommissionSplitBasedOnRoles">
</app-internal-use>
...
<div class="col-sm-5">
<app-plan-effective-date formControlName="effectiveDate" [submitted]="submitted" [minEffectiveDate]="applicationDate$ | async"></app-plan-effective-date>
</div>
effectiveDate.component.html
<label>Effective Date</label>
<div class="input-group margin-xs-bottom-10" [ngClass]="{ 'has-error' : !this.control.valid && (control.touched || submitted) }">
<input class="form-control" [formControl]="control" bsDatepicker required [minDate]="minEffectiveDate"
#dpEffdate="bsDatepicker">
<span class="input-group-addon datepicker-icon" (click)="dpEffdate.toggle()">
<i class="fa fa-calendar"></i>
</span>
</div>
<div class="errorMessage" *ngIf="control.hasError('dateNotLessThanSpecifiedDate') && (submitted || control.touched)">Effective
date cannot be less than the application date</div>
effectiveDate.component.ts
...
export class PlanEffectiveDateComponent extends AbstractValueAccessor implements OnInit, Validator, OnChanges {
@Input() submitted = false;
@Input() minEffectiveDate: Date;
control: FormControl;
constructor(private validatorService: ValidatorService, private cd: ChangeDetectorRef) {
super();
}
ngOnInit() {
this.initializeForm();
this.handleFormChanges();
}
ngOnChanges(changes: SimpleChanges) {
const minEffectiveDateChange = changes['minEffectiveDate'];
if (!!minEffectiveDateChange && !minEffectiveDateChange.firstChange &&
minEffectiveDateChange.currentValue !== minEffectiveDateChange.previousValue &&
!!this.control) {
this.setEffectiveDateValidator();
}
}
initializeForm() {
this.control = new FormControl('', this.composeEffectiveDateValidator());
}
setEffectiveDateValidator() {
this.control.clearValidators();
this.control.setValidators(this.composeEffectiveDateValidator());
setTimeout(() => this.control.updateValueAndValidity({ emitEvent: false }), 0);
this.cd.detectChanges();
}
composeEffectiveDateValidator(): ValidatorFn {
const maxEffectiveDate = utils.currentMoment().add(6, 'month').toDate();
return Validators.compose(
[
this.validatorService.dateNotGreaterThanSpecifiedDate(maxEffectiveDate),
this.validatorService.dateNotLessThanSpecifiedDate(this.minEffectiveDate)
]
);
}
handleFormChanges() {
this.control.valueChanges.subscribe(value => {
this.value = value;
});
}
writeValue(value) {
if (value) {
this.control.setValue(value, { emitEvent: false });
}
}
validate(control: FormControl) {
return this.control.valid ? null : { planEffectiveDateRequired: true };
}
}
dateNotLessThanSpecifiedDate 函数:
dateNotLessThanSpecifiedDate(maxDate: Date) {
return (control: FormControl): { [key: string]: any } => {
if (!!control.value && control.value < maxDate) {
return { 'dateNotLessThanSpecifiedDate': true };
} else {
return null;
}
};
}
任何帮助将不胜感激!
谢谢!
我们使用 ChangeDetectionStragegy.OnPush 解决了这个问题。这是解决方案。
计划有效-date.component.ts
control = new FormControl('', this.buildValidator.bind(this));
constructor(
private cd: ChangeDetectorRef,
private controlDir: NgControl,
) {
super();
this.controlDir.valueAccessor = this;
}
ngOnInit() {
this.handleFormChanges();
this.controlDir.control.setValidators(this.validate.bind(this));
this.updateValidity();
}
updateValidity() {
setTimeout(() => {
this.control.updateValueAndValidity();
this.controlDir.control.setValidators(this.validate.bind(this));
this.cd.detectChanges();
}, 0);
}
在 ngOnChanges 中,调用 updateValidity()
ngOnChanges(changes: SimpleChanges) {
const minEffectiveDateChange = changes['minEffectiveDate'];
const currentPlanEndDateChange = changes['currentPlanEndDate'];
if ((!!minEffectiveDateChange && !minEffectiveDateChange.firstChange &&
minEffectiveDateChange.currentValue !== minEffectiveDateChange.previousValue &&
!!this.control) ||
(!!this.currentPlanEndDate && !currentPlanEndDateChange.firstChange &&
currentPlanEndDateChange.currentValue !== currentPlanEndDateChange.previousValue
&& !!this.control)) {
this.updateValidity();
}
}
buildValidator() 方法只是设置您自定义的验证器。
希望这对和我有类似问题的人有所帮助:)
我在两个单独的组件中有两个日期字段。我在生效日期设置验证以验证生效日期是否早于申请日期。如果早于申请日期,将显示错误消息。
我现在的问题是:如果用户先输入申请日期,然后再输入生效日期,则验证工作正常。但是,如果用户在输入生效日期后更改申请日期,则不会触发验证。换句话说,验证仅在生效日期更改时触发。
当申请日期更改时,如何在生效日期触发验证?我还注意到,当 effectiveDate 早于申请日期时,会显示错误消息。然后我将申请日期更改为有效日期,错误消息不会消失。
我尝试将申请日期传递给 effectiveDate 组件。然而,它并没有像我预期的那样工作。
step1.component.html是调用两个组件的页面。我将 applicationDate$ 作为 [minEffectiveDate]="applicationDate$ | async".
传递给子组件step1.component.html,申请日期在app-internal-use组件里面
<app-internal-use formControlName="internalUse" (brokerSearchIDResult)="addBrokerToApp($event)"
(clientSearchIDResult)="handleClientSearchResult($event)" [shouldShowBrokerSearch]="shouldShowCommissionSplitBasedOnRoles">
</app-internal-use>
...
<div class="col-sm-5">
<app-plan-effective-date formControlName="effectiveDate" [submitted]="submitted" [minEffectiveDate]="applicationDate$ | async"></app-plan-effective-date>
</div>
effectiveDate.component.html
<label>Effective Date</label>
<div class="input-group margin-xs-bottom-10" [ngClass]="{ 'has-error' : !this.control.valid && (control.touched || submitted) }">
<input class="form-control" [formControl]="control" bsDatepicker required [minDate]="minEffectiveDate"
#dpEffdate="bsDatepicker">
<span class="input-group-addon datepicker-icon" (click)="dpEffdate.toggle()">
<i class="fa fa-calendar"></i>
</span>
</div>
<div class="errorMessage" *ngIf="control.hasError('dateNotLessThanSpecifiedDate') && (submitted || control.touched)">Effective
date cannot be less than the application date</div>
effectiveDate.component.ts
...
export class PlanEffectiveDateComponent extends AbstractValueAccessor implements OnInit, Validator, OnChanges {
@Input() submitted = false;
@Input() minEffectiveDate: Date;
control: FormControl;
constructor(private validatorService: ValidatorService, private cd: ChangeDetectorRef) {
super();
}
ngOnInit() {
this.initializeForm();
this.handleFormChanges();
}
ngOnChanges(changes: SimpleChanges) {
const minEffectiveDateChange = changes['minEffectiveDate'];
if (!!minEffectiveDateChange && !minEffectiveDateChange.firstChange &&
minEffectiveDateChange.currentValue !== minEffectiveDateChange.previousValue &&
!!this.control) {
this.setEffectiveDateValidator();
}
}
initializeForm() {
this.control = new FormControl('', this.composeEffectiveDateValidator());
}
setEffectiveDateValidator() {
this.control.clearValidators();
this.control.setValidators(this.composeEffectiveDateValidator());
setTimeout(() => this.control.updateValueAndValidity({ emitEvent: false }), 0);
this.cd.detectChanges();
}
composeEffectiveDateValidator(): ValidatorFn {
const maxEffectiveDate = utils.currentMoment().add(6, 'month').toDate();
return Validators.compose(
[
this.validatorService.dateNotGreaterThanSpecifiedDate(maxEffectiveDate),
this.validatorService.dateNotLessThanSpecifiedDate(this.minEffectiveDate)
]
);
}
handleFormChanges() {
this.control.valueChanges.subscribe(value => {
this.value = value;
});
}
writeValue(value) {
if (value) {
this.control.setValue(value, { emitEvent: false });
}
}
validate(control: FormControl) {
return this.control.valid ? null : { planEffectiveDateRequired: true };
}
}
dateNotLessThanSpecifiedDate 函数:
dateNotLessThanSpecifiedDate(maxDate: Date) {
return (control: FormControl): { [key: string]: any } => {
if (!!control.value && control.value < maxDate) {
return { 'dateNotLessThanSpecifiedDate': true };
} else {
return null;
}
};
}
任何帮助将不胜感激!
谢谢!
我们使用 ChangeDetectionStragegy.OnPush 解决了这个问题。这是解决方案。
计划有效-date.component.ts
control = new FormControl('', this.buildValidator.bind(this));
constructor(
private cd: ChangeDetectorRef,
private controlDir: NgControl,
) {
super();
this.controlDir.valueAccessor = this;
}
ngOnInit() {
this.handleFormChanges();
this.controlDir.control.setValidators(this.validate.bind(this));
this.updateValidity();
}
updateValidity() {
setTimeout(() => {
this.control.updateValueAndValidity();
this.controlDir.control.setValidators(this.validate.bind(this));
this.cd.detectChanges();
}, 0);
}
在 ngOnChanges 中,调用 updateValidity()
ngOnChanges(changes: SimpleChanges) {
const minEffectiveDateChange = changes['minEffectiveDate'];
const currentPlanEndDateChange = changes['currentPlanEndDate'];
if ((!!minEffectiveDateChange && !minEffectiveDateChange.firstChange &&
minEffectiveDateChange.currentValue !== minEffectiveDateChange.previousValue &&
!!this.control) ||
(!!this.currentPlanEndDate && !currentPlanEndDateChange.firstChange &&
currentPlanEndDateChange.currentValue !== currentPlanEndDateChange.previousValue
&& !!this.control)) {
this.updateValidity();
}
}
buildValidator() 方法只是设置您自定义的验证器。
希望这对和我有类似问题的人有所帮助:)