首页 > 解决方案 > Angular 7 Reactive Form Builder,自定义交叉验证器不起作用

问题描述

这是我的 HTML:

<mat-form-field>
    <input matInput type="number" min="0" max="100" step="1" placeholder="Allowed Attendance (%)" required [formControl]="allowed" name="allowed_attendance">
    <mat-error *ngIf="allowed.invalid">Value must be 0-100</mat-error>
</mat-form-field>
<mat-form-field>
    <input matInput type="number" min="0" max="100" step="1" placeholder="Fined Attendance (%)" required [formControl]="fined" name="fined_attendance">
    <mat-error *ngIf="fined.invalid">This value must be less than allowed attendance</mat-error>
</mat-form-field>
<mat-form-field>
    <input matInput required [formControl]="ldo_form_fill_up" placeholder="Applicable Until" [matDatepicker]="picker" name="ldo_form_fill_up">
    <mat-datepicker-toggle #toggle matSuffix [for]="picker"></mat-datepicker-toggle>
    <mat-datepicker #picker></mat-datepicker>
    <mat-error *ngIf="ldo_form_fill_up.invalid">A valid date is required</mat-error>
</mat-form-field>
<mat-form-field *ngIf="ldo_form_fill_up.valid">
    <input matInput required [formControl]="ldo_payment" placeholder="Payable Until" [matDatepicker]="picker2" name="ldo_payment">
    <mat-datepicker-toggle #toggle2 matSuffix [for]="picker2"></mat-datepicker-toggle>
    <mat-datepicker #picker2></mat-datepicker>
    <mat-error *ngIf="ldo_payment.invalid">This date must be greater than the above</mat-error>
</mat-form-field>

以下是 getter 表单控件:

get ldo_form_fill_up() {
  return this.form.get('ldo_form_fill_up');
}

get ldo_payment() {
  return this.form.get('ldo_payment');
}

get allowed() {
  return this.form.get('allowed_attendance');
}

get fined() {
  return this.form.get('fined_attendance');
}

这是表单构建器:

this.form = fb.group({
  allowed_attendance: fb.control(70, [Validators.required, Validators.min(0), Validators.max(100)]),
  fined_attendance: fb.control(60, [Validators.required, Validators.min(0), Validators.max(100)]),
  ldo_form_fill_up: fb.control('', Validators.required),
  ldo_payment: fb.control('', Validators.required),
}, {
  validators: customRangeValidator
});

这是自定义验证器:

export function customRangeValidator(group: FormGroup) {
  const date1 = group.controls.ldo_form_fill_up;
  const date2 = group.controls.ldo_payment;
  const attd1 = group.controls.allowed_attendance;
  const attd2 = group.controls.fined_attendance;
  if (date1.value >= date2.value) {
    date2.setErrors({
      customRangeValidator: true
    });
  }
  if (attd2.value >= attd1.value) {
    attd2.setErrors({
      customRangeValidator: true
    });
  }
  return null;
}

我需要什么:fined_attendance < allowed_attendanceldo_payment > ldo_form_fill_up

到底是怎么回事:

  1. 输入70_allowed_attendance
  2. 输入60_fined_attendance
  3. 没有错误fined_attendance(没关系)。
  4. 更改allowed_attendance50
  5. 显示错误fined_attendance(也可以)。
  6. 再换allowed_attendance一次70
  7. 仍然显示错误。(不行)
  8. 但清除并重新输入60fined_attendance错误消失了!

所以,我面临着显示在的麻烦step 7。我在做什么错?

标签: angularangular-materialangular-reactive-formscross-validationcustomvalidator

解决方案


我认为您只关心设置错误而不是清除它们。

在 else 条件下,您还应该清除它们。就是这样:

import { Component } from '@angular/core';
import { FormBuilder, Validators, FormGroup } from '@angular/forms';

/** @title Simple form field */
@Component({
  selector: 'form-field-overview-example',
  templateUrl: 'form-field-overview-example.html',
  styleUrls: ['form-field-overview-example.css'],
})
export class FormFieldOverviewExample {

  form: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.form = this.fb.group({
      allowed_attendance: this.fb.control(70, [Validators.required, Validators.min(0), Validators.max(100)]),
      fined_attendance: this.fb.control(60, [Validators.required, Validators.min(0), Validators.max(100)]),
      ldo_form_fill_up: this.fb.control('', Validators.required),
      ldo_payment: this.fb.control('', Validators.required),
    }, { validators: customRangeValidator });
  }

  submit() {
    console.log(this.form.value);
  }

  get ldo_form_fill_up() {
    return this.form.get('ldo_form_fill_up');
  }

  get ldo_payment() {
    return this.form.get('ldo_payment');
  }

  get allowed() {
    return this.form.get('allowed_attendance');
  }

  get fined() {
    return this.form.get('fined_attendance');
  }

}

export function customRangeValidator(group: FormGroup) {
  console.log('Called');
  const { ldo_form_fill_up, ldo_payment, allowed_attendance, fined_attendance } = group.controls;
  if (fined_attendance.value >= allowed_attendance.value) {
    fined_attendance.setErrors({ customRangeValidator: true });
  } else {
    fined_attendance.setErrors(null);
  }
  if (ldo_form_fill_up.value >= ldo_payment.value) {
    ldo_payment.setErrors({ customRangeValidator: true });
  } else {
    ldo_payment.setErrors(null);
  }
  return null;
}

此外,在您的模板中,不要使用[formGroup]为什么不简单地使用formGroupName. 像这样的东西:

<form [formGroup]="form">
  <mat-form-field>
    <input matInput type="number" min="0" max="100" step="1" placeholder="Allowed Attendance (%)" required formControlName="allowed_attendance" name="allowed_attendance">
    <mat-error *ngIf="allowed.invalid">Value must be 0-100</mat-error>
  </mat-form-field>
  <mat-form-field>
    <input matInput type="number" min="0" max="100" step="1" placeholder="Fined Attendance (%)" required formControlName="fined_attendance" name="fined_attendance">
    <mat-error *ngIf="fined.invalid">This value must be less than allowed attendance</mat-error>
  </mat-form-field>
  <mat-form-field>
    <input matInput required formControlName="ldo_form_fill_up" placeholder="Applicable Until" [matDatepicker]="picker" name="ldo_form_fill_up">
    <mat-datepicker-toggle #toggle matSuffix [for]="picker"></mat-datepicker-toggle>
    <mat-datepicker #picker></mat-datepicker>
    <mat-error *ngIf="ldo_form_fill_up.invalid">A valid date is required</mat-error>
  </mat-form-field>
  <mat-form-field *ngIf="ldo_form_fill_up.valid">
    <input matInput required formControlName="ldo_payment" placeholder="Payable Until" [matDatepicker]="picker2" name="ldo_payment">
    <mat-datepicker-toggle #toggle2 matSuffix [for]="picker2"></mat-datepicker-toggle>
    <mat-datepicker #picker2></mat-datepicker>
    <mat-error *ngIf="ldo_payment.invalid">This date must be greater than the above</mat-error>
  </mat-form-field>

  <br>

  <button 
    [disabled]="form.invalid"
    mat-raised-button 
    color="primary"
    (click)="submit()">
    Primary
  </button>

</form>

这是您参考的工作示例 StackBlitz


推荐阅读