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



我有一个具有以下结构的示例响应式形式:

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

同级是由子组件呈现的数组。我测试了两种绑定父/子的方法:

1) 使用表单组

<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),但我觉得它更有凝聚力。

以下是比较 2 种策略的完整示例:

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

我对大型 Angular 项目没有太多经验,所以我也想知道是否有任何方法比另一种方法更好地扩展。

谢谢

我看到"表单模型"和"数据模型"之间的一个关键区别是"表单模型"仅包含表单上的实际数据。

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

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

就个人而言,我会始终使用数据模型,因为您可以更好地控制它。您可以更轻松地对其执行操作,例如排序或筛选。您可以更轻松地将其存储在本地存储中以供离线操作。

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

我想你在问 Ng 模型和反应式形式之间的绑定差异

ng-model更适合处理简单的绑定,而reactive formForm操作提供了强大的支持,例如type(如布尔值、字符串、数组等)、structure(重用结构/表单组,如添加具有名字和姓氏的其他人)、validation(自动有效输入和表单)、default value(值变化取决于其他字段),disable

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

我能够使用 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;
}

主要区别在于如何在父级上创建同级表单组:

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),
});
}

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

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上看到:

  • https://stackblitz.com/edit/reactive-forms-binding

相关内容

最新更新