【问题标题】:Automatically populate errors for reactive form controls in Angular 2/4自动填充 Angular 2/4 中反应式表单控件的错误
【发布时间】:2017-09-27 19:30:35
【问题描述】:

我在前端和后端都进行了验证。前端一切正常,但我无法在前端进行后端验证(根据后端验证手动将控件标记为无效)。

问题在于填充有错误的表单控件,看起来我不能只创建this.formBuiltWithFormBuilder.setErrors() 并传递一个有错误的对象来自动填充表单中包含的所有控件 - 因为当所有字段状态保持不变时,只有表单变得无效.

所以目前我正在尝试做类似的事情:

// Example of incoming formErrors:
// (it can also be nested for nested forms)
// {
//    phone: {
//      phoneNumberNoMatch: "The input does not match..."
//    }
// }

@Input() public formErrors: ValidationErrors;
public detailsForm: FormGroup;

public ngOnInit() {
  this.createForm();
}

public ngOnChanges() {
  this.updateFormErrors(this.formErrors);
}

private createForm(account: AccountInterface) {
  this.detailsForm = this.fb.group({
    firstName: ['', Validators.required],
    lastName: ['', Validators.required]
  });
}

private updateFormErrors(errors: any) {
  if (this.detailsForm) {
    // Trying to populate included form controls with errors
    this.detailsForm.setErrors(errors);
  }
}

```

我还考虑过遍历错误对象并为每个控件手动应用错误,但我认为这种解决方案并不理想,因为可能存在嵌套表单。

那么它是一种自动填充错误的表单控件的方法吗?

【问题讨论】:

  • 表单如何知道错误属于哪个控件?
  • 您是否考虑过使用custom validation
  • 嗨 Julia,来自后端的错误与表单控件同名。 @richards,嗯,这可能有道理,但据我所知,有必要手动将自定义验证器绑定到所有表单控件 - 我需要尝试一下。

标签: angular typescript


【解决方案1】:

看起来没有内置解决方案,所以我创建了一个表单助手类来填充错误。理论上它也应该填充嵌套/数组形式,但我只测试了普通形式。如果没有,请告诉我;)

它使用lodash/map 方法遍历错误对象。

import { FormGroup, FormControl, FormArray } from '@angular/forms';
import { map } from 'lodash';

export class FormHelper {
  public static POPULATE_FORM_GROUP_ERRORS(
    rootFormGroup: FormGroup,
    errors: any
  ) {
    map(rootFormGroup.controls, (control, name) => {
      if (control instanceof FormControl) {
        if (errors.hasOwnProperty(name)) {
          control.setErrors(errors[name]);
        }
      }
      if (control instanceof FormGroup) {
        if (errors.hasOwnProperty(name)) {
          FormHelper.POPULATE_FORM_GROUP_ERRORS(control, errors[name]);
        }
      }
      if (control instanceof FormArray) {
        if (errors.hasOwnProperty(name) && errors[name] instanceof Array) {
          this.iterateOverFormArrayControl(control, errors[name]);
        }
      }
    });
  }

  private static iterateOverFormArrayControl(
    formArray: FormArray, 
    errors: any[]
  ) {
    errors.forEach((error: any, index: number) => {
      const arrayControl = formArray.at(index);
      if (arrayControl && arrayControl instanceof FormControl) {
        arrayControl.setErrors(error);
      }
      if (arrayControl && arrayControl instanceof FormGroup) {
        FormHelper.POPULATE_FORM_GROUP_ERRORS(arrayControl, error);
      }
      if (arrayControl && arrayControl instanceof FormArray && error instanceof Array) {
        FormHelper.iterateOverFormArrayControl(arrayControl, error);
      }
    });
  }
}

所以现在我的表单看起来像:

// ... Somewhere at the top
import { FormHelper } from '@app/commons/FormHelper';
// ...

// Example of incoming formErrors:
// (it can also be nested for nested forms)
// {
//    phone: {
//      phoneNumberNoMatch: "The input does not match..."
//    }
// }

@Input() public formErrors: ValidationErrors;
public detailsForm: FormGroup;

public ngOnInit() {
  this.createForm();
}

public ngOnChanges() {
  this.updateFormErrors(this.formErrors);
}

private createForm(account: AccountInterface) {
  this.detailsForm = this.fb.group({
    firstName: ['', Validators.required],
    lastName: ['', Validators.required]
  });
}

private updateFormErrors(errors: any) {
  if (this.detailsForm) {
    // Populate included form controls with errors
   FormHelper.POPULATE_FORM_GROUP_ERRORS(this.detailsForm, errors);
  }
}

【讨论】:

    猜你喜欢
    • 2017-09-25
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多