在Angular上,绑定FormGroup(而不是“真实模型”)是一种不好的做法吗?

时间:2019-02-12 03:27:17

标签: angular architecture angular-reactive-forms

我有一个具有以下结构的样本反应形式:

- id
- firstName
- lastName
- siblings
  - id
  - firstName
  - lastName

兄弟姐妹是由子组件呈现的数组。我测试了绑定父母/孩子的两种方法:

1)使用FormGroup

<app-child *ngFor="let sibling of form.get('siblings').controls" [formGroup]="sibling"></app-child>

2)使用“真实模型”

<app-child *ngFor="let sibling of model.siblings; let i = index;" [model]="sibling" (changed)=updateSiblingModel($event,i)>

两个都很好。我的问题是:是否认为一种方法优于另一种方法?

反应形式与真实模型(由this.form.value获得)几乎是1:1的关系,还有一些有趣的好处,例如级联的验证器和事件。它确实运行良好,但是我感觉我正在从子组件到外部组件中提取“太多的逻辑/结构”。

绑定到模型也可以很好地工作,但是我还有很多工作要做(例如(changed)=updateSiblingModel($event,i),但我觉得它的内聚性更强了。

下面是比较这两种策略的完整示例:

https://stackblitz.com/edit/angular-form-binding

我在大型Angular项目中没有很多经验,所以我也想知道是否有任何一种方法比其他方法更具扩展性。

谢谢

3 个答案:

答案 0 :(得分:3)

我看到的“表单模型”和“数据模型”之间的主要区别在于“表单模型”仅包含表单上实际的数据。

如果您的数据模型具有id属性,则该id很可能不会出现在您的表单中,因此它不会成为“表单模型”的一部分。对于“最后更新日期”或时间戳等可能的其他字段也是如此。

此外,如果以后有人决定将您的某些表单字段进行分组以进行其他验证,则可能会破坏您预期的“表单模型”。

就个人而言,我将始终使用数据模型,因为您可以对其进行更多控制。您可以更轻松地对其执行操作,例如排序或过滤。您可以更轻松地将其存储在本地存储中以进行脱机操作。

此外,如果应用程序随着时间的推移而变大,则可以移至更正式的状态管理库,例如NgRx,它将与“数据模型”一起使用。

答案 1 :(得分:0)

我认为您是在问Ng ModelReactive Forms之间的绑定差异

ng-model更适合处理简单的绑定,而reactive formForm操作(例如type(如布尔值,字符串,数组等),{ {1}}(重用结构/表单组,例如使用姓氏和名字添加其他人),structure(自动验证输入和表单的有效性),validation(值的更改取决于其他字段), default value

简而言之,disable适用于复杂的表单,动态表单(例如字段值或验证更改取决于其他字段)和代码维护。

答案 2 :(得分:0)

我能够使用FormGroup绑定,但将逻辑/结构保留在每个子级中。我找到了这种解决方案,可以为我寻找的目标提供最佳的平衡。

免责声明:我并不是在要求这种解决方案的独创性,它是几天来在互联网上研究和测试许多解决方案的结果。

因此,父组件使用FormGroup绑定到子组件:

<div class="sibling" *ngFor="let sibling of getSiblings(); let i = index;">
    <app-child [form]="sibling" (deleted)="deleteSibling(i)"></app-child>
</div>

父级中的getSiblings()方法只是一个简单的助手:

getSiblings(): AbstractControl[] {
  return (<FormArray>this.form.get('siblings')).controls;
}

主要区别在于如何在父级上创建同级FormGroup:

addSibling() {
  (<FormArray>this.form.controls.siblings).push(ChildComponent.toFormGroup());
}
上面的

addSibling()使用子组件中的静态方法来创建空白FormGroup:

static toFormGroup(model: any = {}) {
  return new FormGroup({
    id: new FormControl(model.id, Validators.required),
    firstName: new FormControl(model.firstName, Validators.required),
    lastName: new FormControl(model.lastName, Validators.required),
  });
}

如上所示,不仅可以创建空白FormGroup。父级上的loadModel方法也可以利用每个子级逻辑来创建归档的FormGroups。在这里,我们只有一种子类型,但我们可以有很多:

loadModel(model: any) {
  this.form.patchValue(model);

  const formArray = this.form.get('siblings') as FormArray;
  while (formArray.length) {
    formArray.removeAt(0);
  }
  model.siblings.forEach(s => formArray.push(ChildComponent.toFormGroup(s)));
}

排序和过滤器也不复杂。这里有多种策略,但是作为一个简单的测试用例:

orderChildren() {
  this.currentModel.siblings = this.currentModel.siblings.sort((a, b) => a.id - b.id);
  this.loadModel(this.currentModel);
}

通过这种方法,我可以使用反应式表单的层叠功能,例如有效状态,原始/脏污标志,更改事件等,同时将每个子级的逻辑/结构保留在其组件类中。举例来说,级联有效性可以在最终解决方案的行动(红色边框)中看到。

由于绑定到FormGroup的主要关注点是必须将子级的逻辑/结构移至父级,因此可以避免这种情况,因此我更愿意接受这不能被视为不良做法

可以在StackBlitz上看到完整的示例:

相关问题