【问题标题】:Angular multiple errors in custom reactive form validator自定义反应形式验证器中的角度多个错误
【发布时间】:2020-01-21 07:05:01
【问题描述】:

我正在验证一个呼叫中心的表单,其中通常会按特定顺序填写字段。如果用户向前跳过,我想为多个字段引发错误。我发现以下方法有效:

  export const recordValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {

    if(!firstField.value && !secondField.Value && !thirdField.value)    
    {
      firstField.setErrors({ "firstFieldError" : true});
      secondField.setErrors({ "secondFieldError" : true});

      return {"firstFieldError" : true, "secondFieldError" : true};

    }
  }

并且 firstField 和 secondField 都正确显示错误。

现在根据docs ValidationErrors 只是错误的映射。但它显然没有任何方法,所以我想我只是将现有映射转换为 ValidationErrors 并返回:

  export const recordValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {

    if(!firstField.value && !secondField.Value && !thirdField.value)    
    {
      firstField.setErrors({ "firstFieldError" : true});
      secondField.setErrors({ "secondFieldError" : true});

      let errorMap = new Map();

      errorMap.set("firstFieldError",true);
      errorMap.set("secondFieldError",true);

      let errorValidators:ValidationErrors = errorMap;

      return errorValidators;

    }
  }

但它不会引发任何错误。

我的模板如下所示:

<mat-form-field>
  <input formControlName="firstField" type="datetime-local" placeholder="First Field" [errorStateMatcher]="errorMatcher" matInput>                        
      <mat-error *ngIf="Form.errors?.firstFieldError">
      First field error!
      </mat-error>
</mat-form-field>

谁能帮我看看为什么第一个有效而第二个无效

【问题讨论】:

  • 因为它不是地图。它是一个具有属性的对象。你的验证器也错了。不建议设置错误。它应该返回 一个对象,告诉 验证表单组或 验证表单控件是否有错误(以及哪些错误)。然后,Angular 根据验证器返回的内容设置组或控制错误和状态。
  • 好的,有道理。那么在多个字段上设置错误的最佳实践是什么?每个控件都应该有自己的验证器吗?
  • 如果一个控件的验证只依赖于它自己的值,那么它应该有它自己的验证器。如果它依赖于其他控件,那么它们应该在一个表单组中,并且应该在表单组上设置验证器。

标签: angular typescript angular-reactive-forms


【解决方案1】:

Jim,自定义验证器不像你说的那样工作。您需要返回一个对象(或 null)。所以你的验证必须喜欢一些像

export const recordValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
    let invalid=false
    const error={}
    if (!control.value.firstField && control.value.secondField)
    {
        error.firstFieldError=true;
        invalid=true;
    }
    if (!control.value.secondField && control.value.thirdField)
    {
        error.secondFieldError=true;
        invalid=true;
    }
    return invalid?error:null;
  }

看看我们如何从“控制”中获取价值——它是表单组——以及我们如何创建一个具有一两个属性的对象——如果你写信检查,你可以在你的 .html 中看到——

{{form.errors|json}}

注意:我真的不了解您的验证器,并想象有人会考虑您问题中的描述

【讨论】:

    【解决方案2】:

    在 angular.io 的 this blogthis reference 的帮助下,我需要回到这个问题并设法妥善解决。

    这是一个返回验证错误映射的验证器:

    import { Injectable } from '@angular/core';
    import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
    
    @Injectable({ providedIn: 'root' })
    export class ShiftTimeValidator {
        constructor() {}
    
        //validate(time: string, shifts: VehicleShift[]): ValidatorFn {
        validate(): ValidatorFn {
    
            return (
                control: AbstractControl,
            ): ValidationErrors => {
    
                let errors:ValidationErrors = {};
    
                // If the form hasn't been touched then don't validate
                if (control.pristine) {
                    null;
                }
    
                // Check if the time falls inside any existing shifts
                if(1 == 1){
                    errors["inside-other-shift"] = true;
                }
    
                // If the time is the start time, then check that it's before the end time
                if(1 == 1){
                    errors["start-before-end"] = true;
                }
    
                // If the time is an end time, check that it's after the start time.
                if(1 == 1){
                    errors["end-before-start"] = true;
                }
    
                // If the this time has an existing match, check that the new shift doesn't overlap any other shifts.
                if(1 == 1){
                    errors["shift-overlap"] = true;
                }
    
                console.log(errors);
    
    
                return errors;
            };
        }
    }
    

    以下是将验证器添加到表单的方法:

    return this.fb.group({
      vehicleShiftId: [],
      vehicleId: [this.vehicle.vehicleId, Validators.required],
      shiftStartTimeString: [, [Validators.required, this.shiftValidator.validate()]],
      shiftEndTimeString: [, Validators.required, this.shiftValidator.validate()],
      vehicleStaff: staffArray
    });
    

    以下是显示错误消息的方法:

    <mat-form-field>
        <input formControlName="shiftStartTimeString" type="time"
        name="shiftStartTime"
        placeholder="Shift start time" [errorStateMatcher]="errorMatcher" matInput>
    
            <mat-error *ngIf="shiftStartTime?.hasError('inside-other-shift')">
            Shift start time is inside another shift.
            </mat-error>
    
            <mat-error *ngIf="shiftStartTime?.hasError('start-before-end')">
            Shift start time is after shift end time.
            </mat-error>
    
            <mat-error *ngIf="shiftStartTime?.hasError('end-before-start')">
            Shift end time is before shift start time.
            </mat-error>
    
            <mat-error *ngIf="shiftStartTime?.hasError('shift-overlap')">
            This shift overlaps another shift.
            </mat-error>
    </mat-form-field>
    

    您是否应该这样做以支持为您尝试验证的每件事创建单独的验证器可能有待讨论,但这证明可以从单个验证器正确返回多个错误。

    【讨论】:

      猜你喜欢
      • 2018-04-02
      • 1970-01-01
      • 1970-01-01
      • 2019-07-26
      • 1970-01-01
      • 1970-01-01
      • 2017-10-06
      • 2018-03-19
      • 2020-01-27
      相关资源
      最近更新 更多