在不同的角度组件中重用FormBuilder Validator

时间:2019-12-11 18:47:57

标签: angular typescript angular-reactive-forms angular8

我后面有一个组件,表单和业务验证器。另外,有显示表单呈现方式的html。

问题是,如果有人想使用带有相同验证器的formbuilder,而又使用完全不同的html呈现方式,怎么办?

如何分隔下面的表单,以便使表单控件和验证器分开,并且与html格式没有强烈的关联?

我们可以导出为类,输入/输出或ControlValueAccessor吗?

当前,这是一个组件。 注意:将需要具有处理更复杂的验证器的能力(例如,所需的城市/州或邮政编码,一个或另一个)

CustomerInfo.component:

打字稿

constructor(
    private formBuilder: FormBuilder,
    private cdr: ChangeDetectorRef
  ) {
    this.addressform = this.formBuilder.group({
      'firstName': [null, [Validators.maxLength(32)]],
      'lastName': [null, [Validators.maxLength(32)]],
      'phone': [null, [Validators.maxLength(32)]],
      'streetName': [null, [Validators.required, Validators.maxLength(64)]],
      'streetType': [null, [Validators.maxLength(8)]],
      'city': [null, [Validators.maxLength(32)]],
      'state': [null, [Validators.maxLength(16)]],
      'postalCode': [null, [Validators.maxLength(16)]],
    },  { validator: atLeastOneLocationRequired })

// City,State  or PostalCode Required

export function atLeastOneLocationRequired(group : FormGroup) : {[s:string ]: boolean} {
      var cityCtrl = group.controls.city;
      var stateCtrl = group.controls.state;
      var postalCodeCtrl = group.controls.postalCode;

      if (cityCtrl != undefined && stateCtrl != undefined && postalCodeCtrl != undefined)
        if (!(((cityCtrl.value && cityCtrl.value.length) && (stateCtrl.value && stateCtrl.value.length)) || (postalCodeCtrl.value && postalCodeCtrl.value.length)))
          return { invalid: true };
}

HTML 。formbuilder稍后将需要其他html格式。

        <div class = "propertysitusaddress">
          <form [formGroup]="addressform">
            <div class = "propertysiteaddresscontainer column">
                <div class = "row title">
                    Address
                </div>  
                <div class = "row">
                    <app-input-textboxc formControlName = "firstName"> </app-input-textbox>
                    <app-input-textbox  formControlName = "lastName"> </app-input-textbox>
                    <app-input-textbox  formControlName = "phone"> </app-input-textbox>
                </div>
                <div class = "row">
                    <app-input-textbox  formControlName = "streetName"> </app-input-textbox>
                    <app-input-textbox  formControlName = "city"> </app-input-textbox>
                    <app-input-textbox  formControlName = "state"> </app-input-textbox>
                </div>
                <div class = "row">
                    <app-input-textbox  formControlName = "postalCode"> </app-input-textbox>
                </div>
            </div>

经常提到将Angular中的智能组件和表示组件分开。

1 个答案:

答案 0 :(得分:2)

我在一个项目中实现了这一点。

方法1

为表单字段创建自定义通用模型。 在您的情况下,每个字段都有一个name和maxLength属性。 因此,您的表单字段模型将如下所示。

export class FormFieldModel {
  name: string;
  label: string;
  fieldConfig: CustomFieldConfig;
}
export class CustomFieldConfig {
  /** whether the property field is editable or not within the form */
  editable: boolean;

  /** optional collection of validators for the form field */
  validators?: ValidatorFn[];

  /** whether the form field is required */
  required = true;

  maxlength?: number;

  /** the control type for the form field */
  type?: 'select' | 'date' | 'number' | 'text' | 'checkbox';

  patternValidationMessage?: string;

  options?: any[];
}

现在在您的每个组件中都需要使用表单。 使用上面的模型构建一个包含所有字段的数组。

示例:

const fields = FormFieldModel[] = [
     {
      name: 'firstName',
      label: 'First Name',
      fieldConfig: {
       maxLength: 32
       // other custom props.
    },
   {
      name: 'lastName',
      label: 'Last Name',
      fieldConfig: {
       maxLength: 32
       // other custom props.
    }
 }

如之前在评论中所述,创建一个服务来创建表单,也可以在单个组件级别上创建它。

  createForm(formList: FormFieldModel []) {
    const form = this.formBuilder.group({ });
    formList.forEach(field => {
      const validators = field.formConfig ? field.formConfig.validators : undefined;
      form.addControl(field.name, this.formBuilder.control(field.value, validators));
    });
    this.addressForm= form; // if this method is at component level
    or
    return form; // if this method is at service layer. 
  }

这样,它也会对您的html有所帮助。 现在,在您的html中。您可以遍历这些字段。

<form [formGroup]="addressForm">
 <div *ngFor="let field in fields>
  <app-input-textbox  formControlName = "field.name"> </app-input-textbox> // you can have a custom component that takes in individual field object and display it accordingly.
</div>
</form>

方法2:

只需将FormGroup和Formbuilder放入导出类中即可。您可以利用您的代码,并在新组件中调用此类。