javascript - 在 Angular 7 中处理大型响应式表单

标签 javascript angular typescript angular-material

我正在尝试找到一种更好的方法来处理复杂的 Angular 形式。 表单真的很大,我需要找到一种方法来降低复杂性。

这是一个表单结构的例子:

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

有些情况下验证器会在运行中发生变化,例如当enableEmailNotification=true 时,组件会添加Required 验证器到notificationsEmail

以下是经过研究的选项:

选项 #0 - 经典

sample on github

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

优点:

  • 代码很多,但很简单

缺点:

  • 所有逻辑都在一个地方。就我而言,这个组件变得太大,难以阅读或维护
  • UI 也变得足够大

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

sample on github

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

优点:

  • 缩小部分 View

缺点:

  • 表单创建和验证规则仍在父组件上
  • 只有 View 尺寸减小了
  • 验证逻辑在根组件中创建,但在子组件中显示错误

选项 #2 - 创建自定义 ControlValueAccessor

sample on github

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

优点:

  • 以多种形式拆分表格。表单可以拆分为更小的独立部分。

缺点:

  • 为表单值保留 JS 对象。看起来不太好

最佳答案

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

@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 ..
    });
  }
}

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

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

关于javascript - 在 Angular 7 中处理大型响应式表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57516787/

相关文章:

javascript - 使用偏移量和 jQuery slider

javascript - 从 mongo 返回的对象中过滤/返回单个嵌套对象(findOne)

javascript - 如何使用 react 形式设置选择值并循环遍历数组

javascript - 尝试使用 Javascript/Jquery 解析 XML 文件时出现错误

javascript - 如何使用 jquery 创建列表

java - 预检响应在 Angular 4 和 Spring Boot (RestAPI) 应用程序中具有无效的 HTTP 状态代码 403

Angular 4 不包含 http 请求的 header

angular - 如何将 ngFor 与两个变量一起使用?

javascript - 创建速记类型时重用扩展接口(interface)的泛型类型

javascript - 在 Ionic 3 应用程序上放置 angular-cli.json 内容的位置