【问题标题】:Angular Custom Cross Field validation on the Form Group not working as expected for date field表单组上的 Angular 自定义交叉字段验证无法按预期对日期字段工作
【发布时间】:2023-03-28 20:58:01
【问题描述】:

我有一个包含开始日期和结束日期的表格。开始日期应该是从第二天开始,结束日期应该是从开始后至少 7 天。我正在使用 Angular 材料日期选择器并为这两个字段设置 minDate 值。我在 FormGroup 级别有一个自定义验证器,用于验证 7 天逻辑并在验证失败时显示 End Date 字段的错误消息。

如果我为结束日期手动输入较旧的日期,验证工作正常并显示错误消息。但是,如果我将开始日期更改为未来日期,然后选择结束日期以使验证失败,则不会显示错误消息。基本上,仅当日期早于最初设置的 minDate 值时才会显示错误消息。对于结束日期大于 minDate 的任何验证失败,不会显示错误。

我的 HTML 代码 -

<form [formGroup]="dateForm" >
  <mat-form-field color="green" appearance="fill" [style.width.px]=300>
    <mat-label>Start Date</mat-label>
    <input matInput [matDatepicker]="picker2" [min]="minDateStart" [max]="maxDate" formControlName="startDate" on/>
    <mat-error>
      <p *ngIf="dateForm.controls.startDate.dirty && dateForm.controls.startDate.errors?.required" class="alert alert-danger">This is a required field</p>
      <p *ngIf="dateForm.controls.startDate.dirty && dateForm.controls.startDate.errors?.invalidStartDate" class="alert alert-danger">
          {{ dateForm.controls.startDate.errors?.invalidStartDate.message}} </p>
    </mat-error>
    <mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle>
    <mat-datepicker #picker2 color="primary"></mat-datepicker>
  </mat-form-field>
  &nbsp;
  <mat-form-field color="green" appearance="fill" [style.width.px]=300>
    <mat-label>End Date</mat-label>
    <input matInput [matDatepicker]="picker3" [min]="minDateEnd" [max]="maxDate" formControlName="endDate"/>
    <mat-error>
      <p *ngIf="dateForm.controls.endDate.touched && dateForm.controls.endDate.errors?.required" class="alert alert-danger">This is a required field</p>
      <p *ngIf="dateForm.errors?.invalidEndDate" class="alert alert-danger">
        {{ dateForm.errors?.invalidEndDate.message}} </p>
    </mat-error>
    <mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle>
    <mat-datepicker #picker3></mat-datepicker>
  </mat-form-field>
</form>

我的 TS 文件 -

const DATE_OFFSET_START = 1;
const DATE_OFFSET_END = 7;

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'Date Picker Validation Issue';

  minDateStart: Date;
  minDateEnd: Date;
  maxDate: Date;
  dateForm: FormGroup

  constructor(
    private formBuilder: FormBuilder) {
  }

  ngOnInit() {
    const currentDate = new Date();
    const currentYear = currentDate.getFullYear();
    const currentDay = currentDate.getUTCDate();
    const currentMonth = currentDate.getUTCMonth();

    this.minDateEnd = new Date(currentYear, currentMonth, currentDay + DATE_OFFSET_START + DATE_OFFSET_END);
    this.minDateStart = new Date(currentYear, currentMonth, currentDay + DATE_OFFSET_START);
    this.maxDate = new Date(currentYear + 999, currentMonth, currentDay);

    this.dateForm = this.formBuilder.group({
      startDate: [this.minDateStart, [Validators.required, validateStartDate]],
      endDate: [this.minDateEnd, [Validators.required]],
    }, { validators: validateEndDate('startDate', 'endDate') });
  }

}

// Validates the Form Group dates values.
// Returns error message if difference is less than specified limit.
export function validateEndDate(startDateFieldName: string, endDateFieldName: string) {
  return (fg: FormGroup) => {
    if (fg.get(endDateFieldName).value === undefined || fg.get(endDateFieldName).value == null)
      return null;
    let startDate = new Date(fg.get(startDateFieldName).value);
    let endDate = new Date(fg.get(endDateFieldName).value);

    return dateDifference(startDate, endDate) >= DATE_OFFSET_END ? null : {
      invalidEndDate: {
        message: "End Date should be atleast " + DATE_OFFSET_END + " days more than Start date!"
      }
    };
  }
}

validateEndDate 是验证开始和结束日期的自定义验证器 { validators: validateEndDate('startDate', 'endDate') });

这是显示错误的代码 -

      <p *ngIf="dateForm.controls.endDate.touched && dateForm.controls.endDate.errors?.required" class="alert alert-danger">This is a required field</p>
      <p *ngIf="dateForm.errors?.invalidEndDate" class="alert alert-danger">
        {{ dateForm.errors?.invalidEndDate.message}} </p>
    </mat-error>

我不确定为什么仅当日期小于 minDate 值时才显示错误,而不是针对所有验证错误。

【问题讨论】:

    标签: angular datepicker angular-material angular-validation angular-custom-validators


    【解决方案1】:

    我遇到这个问题不是因为我的自定义日期验证器,而是问题在于有角度的材料形式。我看到你没有在&lt;input&gt; 标签中设置errorStateMatcher 属性。当我使用这个属性时,一切正常。当您要检查父表单组是否无效时,可以使用matInputerrorStateMatcher 属性,如doc 中所述。

    例如:

    HTML中带有errorStateMatcher的dueDate字段:

    <mat-form-field appearance="fill" class="full-width">
      <mat-label>Due Date</mat-label>
      <input matInput [matDatepicker]="picker"
             formControlName="dueDate"
             id="dueDate"
             [min]="minDate"
             [errorStateMatcher]="matcher">
      <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
      <mat-datepicker #picker touchUi></mat-datepicker>
      <mat-error *ngIf="createTaskForm.errors?.dueDateGtEqRepeatUntil">
        DueDate should not be greater than or equal to Repeat Until Date.
      </mat-error>
      <mat-error *ngIf="createTaskForm.controls?.dueDate.hasError('required')">
        Due date is required.
      </mat-error>
    </mat-form-field>
    

    在 TS 文件中:

    export class MyErrorStateMatcher implements ErrorStateMatcher {
      isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
        const invalidCtrl = control && control.invalid;
        const invalidParent = control && control.parent && control.parent.invalid;
        return (invalidCtrl || invalidParent) && (control.dirty || control.touched);
      }
    }
    

    我希望这能解决您的问题。有关两个日期字段之间交叉验证的其他详细信息,this video 可能有用。

    【讨论】:

    • 谢谢,它就像一个魅力。我删除了&amp;&amp; (control.dirty || control.touched) 条件,以便在更改开始日期后立即显示错误。
    • 当我在现有表单中使用它时,如果表单中的任何其他字段无效,那么由于control.parent.invalid 条件,该字段也会被突出显示为错误。我已经修改了检查特定错误的方法以解决此问题。 const invalidCtrl = control &amp;&amp; control.invalid; const invalidEndDate = control &amp;&amp; control.parent &amp;&amp; control.parent.hasError('invalidEndDate'); return (invalidCtrl || invalidEndDate);
    猜你喜欢
    • 2017-07-19
    • 1970-01-01
    • 1970-01-01
    • 2019-07-04
    • 2023-03-14
    • 2018-09-09
    • 2018-11-27
    • 2019-05-08
    • 1970-01-01
    相关资源
    最近更新 更多