57
задан 27 April 2019 в 13:09

2 ответа

На основе ответ @MixerOID , вот мое конечное решение как компонент (возможно, я создаю библиотеку). Я также поддерживаю FormArray:

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>
1
ответ дан 1 November 2019 в 16:04

Это - другой вариант, который собирает ошибки рекурсивно и не зависит ни от какой внешней библиотеки как 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;
  }
}
5
ответ дан 1 November 2019 в 16:04

Другие вопросы по тегам:

Похожие вопросы: