angular - Angular forms: best practise for complex nested reactive forms and validation at root component
问题描述
I've been struggling for a few days to find a good pattern for my use case. I have a very complex reactive form, full of nested components, some fields are required, some fields may appear given certain conditions, etc... and this is creating a huge problem maintaining the code. The approach I used so far it passing the formControl to the children components and populate from there, but things started getting really hard to debug given the size of the form. A must for this form is that on submit of the whole form, a validation of all the nested fields is performed, and markAsTouched any field that is required but hasn't been inserted. I have been exploring 2 approaches but none of the 2 seems to be of any help:
- Control Value Accessor: the concept is perfect, the logic is split perfectly among the children without the parent having to concern about it, but the CON is that the children controllers are not exposed and I can't markAsTouched all the sub forms to show the respective errors
- Control Container: This approach seems to be needing all of the controls to be defined at the parent level, but being a very big form, it seems really counterproductive and not really solving my problem.
I wonder if anyone has any experience with such forms and able to provide some guidance on what are the best practises in this case. I have made a very simple stackblitz with just one sub child using Control Container, unfortunately I wasn't able to make it run https://stackblitz.com/edit/angular-ivy-axbgr5
解决方案
Angular 中的复杂表单可能是个大麻烦。根据我的经验,最好的方法是创建一个有状态的父组件和许多子无状态组件。
父组件需要专用于特定表单。子组件可以在任何地方多次重用。
父组件规则:
- 有状态的
- 创建并保存表单定义
- 在每次表单更改时发出表单状态(值、有效、原始)
- 保存自定义验证逻辑
子组件规则:
- 无国籍
FormGroups
从父级接收表单部件(嵌套)- 没有自定义验证逻辑
在上述场景中,子组件是没有任何验证逻辑的“可重用视图”。它总是来自父母。
如何将表单部件传递给子组件?
FormGroups
您可以通过以下方式传递嵌套:
- 通过
Input
(https://github.com/p-programowanie/angular-forms/tree/forms-form-group) - 通过
ControlContainer
和构造函数注入(https://github.com/p-programowanie/angular-forms/tree/forms-control-container) - 通过
ControlContainer
和viewProvider
注入(https://github.com/p-programowanie/angular-forms/tree/forms-control-container-provider)
控制值访问器
在我看来,ControlValueAccessor
用于创建表单部件不是一个好主意。验证逻辑被封装在里面。这是创建一些非常困难的部分(例如“颜色选择器”)的好方法,而不仅仅是具有多个字段的“客户地址”。
组件外的业务逻辑
我还尝试使用以下简单代码将业务逻辑移出组件:
constructor(public businessLogic: VendorBusinessLogicService) { }
ngOnInit() {
this.form = this.businessLogic.createForm(this.initialValue);
this.subscription = this.form.valueChanges.subscribe(value => {
this.businessLogic.applyBusinessLogic(value);
this.emitFormState();
});
this.emitFormState();
}
当然,要求是在服务内部保存表单引用。老实说,我看不到它的好处。这种业务逻辑服务看起来很吓人。(https://github.com/p-programowanie/angular-forms/tree/forms-separated-business-logic)
推荐阅读
- javascript - 如何在 Vue 3 运行时将组件渲染为其 HTML 字符串
- python - 如何跟踪 SQLAlchemy 表连接/锁
- c# - 用于目录路径格式验证的正则表达式
- c - 使用 memcpy 将额外的 \377 复制到缓冲区 char 数组
- javascript - 为什么使用 React Js 过滤状态不返回数据
- python - Discord.py ban 命令错误:NameError:未定义名称“客户端”
- javascript - 使 div 能够在单击时运行 onclick 函数
- python - py2exe 不工作,找不到 libvorbisfile-3.dll
- apache-spark - spark如何向驱动节点指示一项已完成?
- list - 在 Map Netlogo 中设置变量