รับข้อผิดพลาดในการตรวจสอบความถูกต้องทั้งหมดจาก Angular 2 FormGroup


92

ให้รหัสนี้:

this.form = this.formBuilder.group({
      email: ['', [Validators.required, EmailValidator.isValid]],
      hasAcceptedTerms: [false, Validators.pattern('true')]
    });

ฉันจะรับข้อผิดพลาดในการตรวจสอบความถูกต้องทั้งหมดได้this.formอย่างไร?

ฉันกำลังเขียนการทดสอบหน่วยและต้องการรวมข้อผิดพลาดในการตรวจสอบความถูกต้องจริงไว้ในข้อความยืนยัน


แทนที่จะเป็น Validators.pattern ('true') คุณสามารถ / ควรใช้ Validators.requiredTrue เพื่อบังคับให้มีการเลือกช่องทำเครื่องหมาย
เป็นโมฆะ

คำตอบ:


146

ฉันพบปัญหาเดียวกันและเพื่อค้นหาข้อผิดพลาดในการตรวจสอบความถูกต้องทั้งหมดและแสดงขึ้นฉันจึงเขียนวิธีการถัดไป:

getFormValidationErrors() {
  Object.keys(this.productForm.controls).forEach(key => {

  const controlErrors: ValidationErrors = this.productForm.get(key).errors;
  if (controlErrors != null) {
        Object.keys(controlErrors).forEach(keyError => {
          console.log('Key control: ' + key + ', keyError: ' + keyError + ', err value: ', controlErrors[keyError]);
        });
      }
    });
  }

productFormควรเปลี่ยนชื่อแบบฟอร์มเป็นของคุณ

มันทำงานในวิธีถัดไป: เราได้รับการควบคุมทั้งหมดของเราจากรูปแบบในรูปแบบ{[p: string]: AbstractControl}และทำซ้ำตามคีย์ข้อผิดพลาดแต่ละอันเพื่อรับรายละเอียดของข้อผิดพลาด มันข้ามnullค่าความผิดพลาด

นอกจากนี้ยังสามารถเปลี่ยนแปลงได้สำหรับการแสดงข้อผิดพลาดในการตรวจสอบความถูกต้องในมุมมองเทมเพลตเพียงแค่แทนที่console.log(..)สิ่งที่คุณต้องการ


2
จะขยายวิธีการข้างต้นสำหรับ FormArray ในรูปแบบเดียวกันได้อย่างไร?
Mohammad Sharaf Ali

คุณหมายถึง' + controlErrors[keyErrors];แทนที่จะเป็น', controlErrors[keyErrors];?
ryanm

@ryanm ไม่มีความแตกต่างในการพิมพ์เช่นวัตถุหรือเช่นค่าสตริง
Alex Efimov

ฉันจะนำเข้าValidationErrorsในเชิงมุม 2 ได้จากที่ใด
sainu

import { ValidationErrors } from '@angular/forms';
Craig Wayne

31

นี่คือโซลูชันที่มีการFormGroupรองรับภายใน ( เช่นที่นี่ )

ทดสอบกับ: Angular 4.3.6

รับแบบฟอร์มตรวจสอบข้อผิดพลาด.ts

import { AbstractControl, FormGroup, ValidationErrors } from '@angular/forms';

export interface AllValidationErrors {
  control_name: string;
  error_name: string;
  error_value: any;
}

export interface FormGroupControls {
  [key: string]: AbstractControl;
}

export function getFormValidationErrors(controls: FormGroupControls): AllValidationErrors[] {
  let errors: AllValidationErrors[] = [];
  Object.keys(controls).forEach(key => {
    const control = controls[ key ];
    if (control instanceof FormGroup) {
      errors = errors.concat(getFormValidationErrors(control.controls));
    }
    const controlErrors: ValidationErrors = controls[ key ].errors;
    if (controlErrors !== null) {
      Object.keys(controlErrors).forEach(keyError => {
        errors.push({
          control_name: key,
          error_name: keyError,
          error_value: controlErrors[ keyError ]
        });
      });
    }
  });
  return errors;
}

ใช้ตัวอย่าง :

if (!this.formValid()) {
  const error: AllValidationErrors = getFormValidationErrors(this.regForm.controls).shift();
  if (error) {
    let text;
    switch (error.error_name) {
      case 'required': text = `${error.control_name} is required!`; break;
      case 'pattern': text = `${error.control_name} has wrong pattern!`; break;
      case 'email': text = `${error.control_name} has wrong email format!`; break;
      case 'minlength': text = `${error.control_name} has wrong length! Required length: ${error.error_value.requiredLength}`; break;
      case 'areEqual': text = `${error.control_name} must be equal!`; break;
      default: text = `${error.control_name}: ${error.error_name}: ${error.error_value}`;
    }
    this.error = text;
  }
  return;
}

1
การเปลี่ยนแปลงเชิงมุม 5 - const controlErrors: ValidationErrors = form.controls [key] .errors;
Kris Kilton

คำแนะนำในการตรวจสอบความจริงบนcontrolErrors IE if (controlErrors) {เนื่องจากการตรวจสอบเท่านั้นnullจะให้ข้อผิดพลาดหากเกิดข้อผิดพลาดundefined
mtholen

8

นี่เป็นตัวแปรอื่นที่รวบรวมข้อผิดพลาดซ้ำและไม่ขึ้นอยู่กับไลบรารีภายนอกใด ๆ เช่นlodash(ES6 เท่านั้น):

function isFormGroup(control: AbstractControl): control is FormGroup {
  return !!(<FormGroup>control).controls;
}

function collectErrors(control: AbstractControl): any | null {
  if (isFormGroup(control)) {
    return Object.entries(control.controls)
      .reduce(
        (acc, [key, childControl]) => {
          const childErrors = collectErrors(childControl);
          if (childErrors) {
            acc = {...acc, [key]: childErrors};
          }
          return acc;
        },
        null
      );
  } else {
    return control.errors;
  }
}

6

วิธีเรียกดูข้อผิดพลาดทั้งหมดจากรูปแบบเชิงมุมหลังจากสร้างโครงสร้างสูตรใด ๆ แล้วจะไม่มีทางดึงข้อผิดพลาดทั้งหมดจากแบบฟอร์มได้ สิ่งนี้มีประโยชน์มากสำหรับวัตถุประสงค์ในการดีบัก แต่ยังสำหรับการพล็อตข้อผิดพลาดเหล่านั้นด้วย

ผ่านการทดสอบสำหรับ Angular 9

getFormErrors(form: AbstractControl) {
    if (form instanceof FormControl) {
        // Return FormControl errors or null
        return form.errors ?? null;
    }
    if (form instanceof FormGroup) {
        const groupErrors = form.errors;
        // Form group can contain errors itself, in that case add'em
        const formErrors = groupErrors ? {groupErrors} : {};
        Object.keys(form.controls).forEach(key => {
            // Recursive call of the FormGroup fields
            const error = this.getFormErrors(form.get(key));
            if (error !== null) {
                // Only add error if not null
                formErrors[key] = error;
            }
        });
        // Return FormGroup errors or null
        return Object.keys(formErrors).length > 0 ? formErrors : null;
    }
}

ฉันใช้ Angular 7 และทำการแก้ไขโค้ดของคุณสองครั้ง: form.errors ?? nullฉันต้องลบ ?? เพื่อรวบรวม ที่สำคัญกว่านั้นในเงื่อนไขการตรวจสอบ FormGroup ฉันได้เพิ่ม|| formParameter instanceof FormArrayสิ่งที่เปิดแอปพลิเคชันของฉันขึ้นมาจริงๆ ขอบคุณ!
Tyler Forsythe

6

หรือคุณสามารถใช้ไลบรารีนี้เพื่อรับข้อผิดพลาดทั้งหมดแม้ในรูปแบบลึกและไดนามิก

npm i @naologic/forms

หากคุณต้องการใช้ฟังก์ชันคงที่ในแบบฟอร์มของคุณเอง

import {NaoFormStatic} from '@naologic/forms';
...
const errorsFlat = NaoFormStatic.getAllErrorsFlat(fg); 
console.log(errorsFlat);

หากคุณต้องการใช้NaoFromGroupคุณสามารถนำเข้าและใช้งานได้

import {NaoFormGroup, NaoFormControl, NaoValidators} from '@naologic/forms';
...
    this.naoFormGroup = new NaoFormGroup({
      firstName: new NaoFormControl('John'),
      lastName: new NaoFormControl('Doe'),
      ssn: new NaoFormControl('000 00 0000', NaoValidators.isSSN()),
    });

   const getFormErrors = this.naoFormGroup.getAllErrors();
   console.log(getFormErrors);
   // --> {first: {ok: false, isSSN: false, actualValue: "000 00 0000"}}

อ่านเอกสารฉบับเต็ม


2

จากการตอบกลับ@MixerOIDนี่คือโซลูชันสุดท้ายของฉันในฐานะคอมโพเนนต์ (ฉันอาจสร้างไลบรารี) ฉันยังสนับสนุน FormArray's:

import {Component, ElementRef, Input, OnInit} from '@angular/core';
import {FormArray, FormGroup, ValidationErrors} from '@angular/forms';
import {TranslateService} from '@ngx-translate/core';

interface AllValidationErrors {
  controlName: string;
  errorName: string;
  errorValue: any;
}

@Component({
  selector: 'app-form-errors',
  templateUrl: './form-errors.component.html',
  styleUrls: ['./form-errors.component.scss']
})
export class FormErrorsComponent implements OnInit {

  @Input() form: FormGroup;
  @Input() formRef: ElementRef;
  @Input() messages: Array<any>;

  private errors: AllValidationErrors[];

  constructor(
    private translateService: TranslateService
  ) {
    this.errors = [];
    this.messages = [];
  }

  ngOnInit() {
    this.form.valueChanges.subscribe(() => {
      this.errors = [];
      this.calculateErrors(this.form);
    });

    this.calculateErrors(this.form);
  }

  calculateErrors(form: FormGroup | FormArray) {
    Object.keys(form.controls).forEach(field => {
      const control = form.get(field);
      if (control instanceof FormGroup || control instanceof FormArray) {
        this.errors = this.errors.concat(this.calculateErrors(control));
        return;
      }

      const controlErrors: ValidationErrors = control.errors;
      if (controlErrors !== null) {
        Object.keys(controlErrors).forEach(keyError => {
          this.errors.push({
            controlName: field,
            errorName: keyError,
            errorValue: controlErrors[keyError]
          });
        });
      }
    });

    // This removes duplicates
    this.errors = this.errors.filter((error, index, self) => self.findIndex(t => {
      return t.controlName === error.controlName && t.errorName === error.errorName;
    }) === index);
    return this.errors;
  }

  getErrorMessage(error) {
    switch (error.errorName) {
      case 'required':
        return this.translateService.instant('mustFill') + ' ' + this.messages[error.controlName];
      default:
        return 'unknown error ' + error.errorName;
    }
  }
}

และ HTML:

<div *ngIf="formRef.submitted">
  <div *ngFor="let error of errors" class="text-danger">
    {{getErrorMessage(error)}}
  </div>
</div>

การใช้งาน:

<app-form-errors [form]="languageForm"
                 [formRef]="formRef"
                 [messages]="{language: 'Language'}">
</app-form-errors>

2

ลองสิ่งนี้จะเรียกการตรวจสอบความถูกต้องสำหรับการควบคุมทั้งหมดในรูปแบบ:

validateAllFormControl(formGroup: FormGroup) {         
  Object.keys(formGroup.controls).forEach(field => {  
    const control = formGroup.get(field);             
    if (control instanceof FormControl) {             
      control.markAsTouched({ onlySelf: true });
    } else if (control instanceof FormGroup) {        
      this.validateAllFormControl(control);            
    }
  });
}

1
export class GenericValidator {
    constructor(private validationMessages: { [key: string]: { [key: string]: string } }) {
    }

processMessages(container: FormGroup): { [key: string]: string } {
    const messages = {};
    for (const controlKey in container.controls) {
        if (container.controls.hasOwnProperty(controlKey)) {
            const c = container.controls[controlKey];
            if (c instanceof FormGroup) {
                const childMessages = this.processMessages(c);
                // handling formGroup errors messages
                const formGroupErrors = {};
                if (this.validationMessages[controlKey]) {
                    formGroupErrors[controlKey] = '';
                    if (c.errors) {
                        Object.keys(c.errors).map((messageKey) => {
                            if (this.validationMessages[controlKey][messageKey]) {
                                formGroupErrors[controlKey] += this.validationMessages[controlKey][messageKey] + ' ';
                            }
                        })
                    }
                }
                Object.assign(messages, childMessages, formGroupErrors);
            } else {
                // handling control fields errors messages
                if (this.validationMessages[controlKey]) {
                    messages[controlKey] = '';
                    if ((c.dirty || c.touched) && c.errors) {
                        Object.keys(c.errors).map((messageKey) => {
                            if (this.validationMessages[controlKey][messageKey]) {
                                messages[controlKey] += this.validationMessages[controlKey][messageKey] + ' ';
                            }
                        })
                    }
                }
            }
        }
    }
    return messages;
}
}

ฉันเอามันมาจากDeborahkและปรับเปลี่ยนเล็กน้อย


1
// IF not populated correctly - you could get aggregated FormGroup errors object
let getErrors = (formGroup: FormGroup, errors: any = {}) {
  Object.keys(formGroup.controls).forEach(field => {
    const control = formGroup.get(field);
    if (control instanceof FormControl) {
      errors[field] = control.errors;
    } else if (control instanceof FormGroup) {
      errors[field] = this.getErrors(control);
    }
  });
  return errors;
}

// Calling it:
let formErrors = getErrors(this.form);

0

คุณสามารถวนซ้ำผ่านคุณสมบัติ this.form.errors


14
ฉันเดาว่าthis.form.errorsจะส่งคืนเฉพาะข้อผิดพลาดของการตรวจสอบความถูกต้องthis.formไม่ใช่สำหรับthis.form.controls. คุณสามารถตรวจสอบความถูกต้องของ FormGroups และกลุ่มย่อย (จำนวน FormGroups, FormControls และ FormArrays โดยพลการ) แยกกัน ในการดึงข้อผิดพลาดทั้งหมดฉันคิดว่าคุณต้องถามซ้ำ
Risto Välimäki

0

สำหรับต้นไม้ FormGroup ขนาดใหญ่คุณสามารถใช้ lodash เพื่อล้างต้นไม้และรับโครงสร้างของตัวควบคุมที่มีข้อผิดพลาด สิ่งนี้ทำได้โดยการทำซ้ำผ่านการควบคุมเด็ก (เช่นการใช้allErrors(formGroup)) และตัดกลุ่มการควบคุมย่อยที่ถูกต้องทั้งหมด:

private isFormGroup(control: AbstractControl): control is FormGroup {
  return !!(<FormGroup>control).controls;
}

// Returns a tree of any errors in control and children of control
allErrors(control: AbstractControl): any {
  if (this.isFormGroup(control)) {
    const childErrors = _.mapValues(control.controls, (childControl) => {
      return this.allErrors(childControl);
    });

    const pruned = _.omitBy(childErrors, _.isEmpty);
    return _.isEmpty(pruned) ? null : pruned;
  } else {
    return control.errors;
  }
}

-2

ฉันใช้เชิงมุม 5 และคุณสามารถตรวจสอบคุณสมบัติสถานะของแบบฟอร์มของคุณได้โดยใช้ FormGroup เช่น

this.form = new FormGroup({
      firstName: new FormControl('', [Validators.required, validateName]),
      lastName: new FormControl('', [Validators.required, validateName]),
      email: new FormControl('', [Validators.required, validateEmail]),
      dob: new FormControl('', [Validators.required, validateDate])
    });

this.form.status จะเป็น "ไม่ถูกต้อง" เว้นแต่ว่าทุกช่องจะผ่านกฎการตรวจสอบทั้งหมด

ส่วนที่ดีที่สุดคือตรวจจับการเปลี่ยนแปลงแบบเรียลไทม์


1
ใช่ แต่เราจำเป็นต้องได้รับข้อผิดพลาดของกลุ่มฟอร์มทั้งหมดไม่ใช่แค่รู้ว่ามันไม่ถูกต้อง
Motassem MK

OP ต้องการข้อความตรวจสอบความถูกต้องซึ่งไม่รวมอยู่ในคุณสมบัติสถานะเนื่องจากเป็นเพียงบูลีน
Stefan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.