首页 > 解决方案 > 在 Angular 7 中处理大型响应式表单

问题描述

我试图找到一种更好的方法来处理复杂的角度形式。表格真的很大,我需要找到一种方法来降低复杂性。

以下是表单结构的示例:

{
    "fieldA" : ...,
    "fieldB" : ...,
    "fieldC" : ...,
    "profile": {
        "username": ...,
        "email": ...,
        "firstName": ...,
        "lastName": ...,
        ...
    },
    "settings": {
        "enableEmailNotification": ...,
        "notificationsEmail": ..., // required when enableEmailNotification
        ...
    },
    ...
}

在某些情况下,验证器会即时更改,例如,当enableEmailNotification=true组件将Required验证器添加到notificationsEmail

以下是研究的选项:

选项 #0 - 经典

github上的示例

这种方法使用一种形式和一种组件。

优点:

缺点:

选项 #1 - 将 FormGroup 传递给子组件

github上的示例

这种方法将作为属性发送formGroup到内部组件。@Input()

优点:

缺点:

选项 #2 - 创建自定义 ControlValueAccessor

github上的示例

基于这篇文章,我们可以创建自定义的 ControlValueAccessor,它将为表单的一部分返回一个对象。

优点:

缺点:

标签: javascriptangulartypescriptangular-material

解决方案


我对大型复杂表单的策略是拥有一个包装组件和子组件。每个子组件都有自己的表单服务,并且包装器有一个主表单服务,其中注入了子表单服务,考虑一下

@Component({
  selector: 'form-wrapper',
  template: `
    <form [formGroup]="form" (submit)="save()">
      <sub-form-a></sub-form-a>
      <sub-form-b></sub-form-b>
      <input type="submit" value="Submit Form">
    </form>
  `,
  providers: [MasterFormService, FormAService, FormBService]
})
export class FormWrapper {
  constructor(private formService: MasterFormService) { }
  save() {
    // whatever save actions here
  }
}

@Component({ // form b compoent is basically the same
  selector: 'sub-form-a',
  template: `
    ... whatever template belongs to form a ..
  `
})
export class FormAComponent {
  form: FormGroup
  constructor(private formService: FormAService) {
    this.form = this.formService.form;
    // form a specific actions
  }
}

@Injectable()
export class MasterFormService {
  form: FormGroup;
  constructor(private fb: FormBuilder, formAService: FormAService, formBService: FormBService) {
    this.form = this.fb.group({
      groupA: this.formAService.form,
      groupB: this.formBService.form,
    });
  }
}

@Injectable() // formB service is basically the same
export class FormAService {
  form: FormGroup;
  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      .. whatever fields belong to form a ..
    });
  }
}

此方法创建高度可重用的子表单,并允许您模块化/隔离表单逻辑和模板。我经常发现子表单通常属于多个地方,因此它使我的代码非常干燥。特别是在您的示例中,您可以轻松地在应用程序的其他地方重用设置表单和配置文件表单组件。一两次我什至再次嵌套这个结构以获得极其复杂的形式。

缺点是结构可能看起来很复杂,但你很快就习惯了。


推荐阅读