- 首页
- 其他开发
- Angular Reative Forms >用户自定义表单错误
Angular Reative Forms >用户自定义表单错误
[英] Angular Reative Forms > User customized forms error
本文介绍了Angular Reative Forms >用户自定义表单错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在尝试在我的 angular 应用程序上实现一项功能,用户可以在其中创建自己的表单(选择字段/验证/等).一旦他们创建了表单,我会将它的 JSON 结构存储在数据库中以备后用:
导出接口 FormModel {id:字符串;名称:字符串;类型:'组' |'控制';儿童:FormModel[];isArray:布尔值;}
示例结构是这样的:
<代码>[{id: '用户',name: '用户',类型:'组',isArray: 真,孩子们: [{id:用户",name: "用户",类型:'组',isArray:假,孩子们: [{id: "姓名",name: "姓名",类型:'控制',儿童:空,isArray: 假},{id:年龄",姓名年龄",类型:'控制',儿童:空,isArray: 假}]},{id:用户",name: "用户",类型:'组',isArray:假,孩子们: [{id: "姓名",name: "姓名",类型:'控制',儿童:空,isArray:假,},{id:年龄",姓名年龄",类型:'控制',儿童:空,isArray: 假}]}]}, {id: '评论',name: '评论',类型:'控制',儿童:空,isArray: 假}];
根据从数据库加载的 JSON 创建反应式表单后,我在创建相应的 html 时遇到了困难,因为它具有递归性.
经过多次尝试,我设法得到了以下内容,它生成了一个类似于我理解的应该需要的 HTML:
<div formArrayName="0"><div formGroupName="用户"><input type="text" formControlName="name"><input type="text" formControlName="age">
<div formArrayName="0"><div formGroupName="用户"><input type="text" formControlName="name"><input type="text" formControlName="age">
我使用的模板如下:
<div *ngIf="item?.children?.length > 0 && !item.isArray" [formGroupName]="item.id"><ng-容器*ngTemplateOutlet="recursiveList; context:{ $implicit: item.children, prefix: item.isArray }"></ng-容器>
</ng-容器></ng-模板><ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: formFields, prefix: '' }"></ng-容器><ng-template #recursiveArray let-controls let-prefix="prefix"><ng-container *ngFor="let item of control; let i = index;"><div [formGroupName]="i"><input type="text" [formControlName]="item.id" *ngIf="(item?.children?.length > 0) == false"><div *ngIf="item?.children?.length > 0 && item.isArray" [formArrayName]="item.id"><ng-容器*ngTemplateOutlet="recursiveArray; context:{ $implicit: item.children, prefix: item.isArray }"></ng-容器>
<div *ngIf="item?.children?.length > 0 && !item.isArray" [formGroupName]="item.id"><ng-容器*ngTemplateOutlet="recursiveList; context:{ $implicit: item.children, prefix: item.isArray }"></ng-容器>
</ng-容器></ng-模板>
</表单>
在我看来这是正确的,但我不断收到错误:
错误错误:找不到带有路径的控件:'变量 ->0'错误错误:找不到带有路径的控件:'变量 ->0 ->用户'
我用示例创建了一个stackblitz:https://stackblitz.com/edit/angular-mtbien
你们能帮我找出问题吗?我已经为此工作了 2 天没有任何成功:(
谢谢!
解决方案
正如 Ersenkoening 所说,对于 FormsGroup 和 Form Arrays,您可以直接使用控件".使用 FormArrayName、Form Group 等,真的很头疼.
看到 Ersenkoening 的 form-array.component.html 可以更简单的编码为
<ng-container *ngFor="let child of formArray.controls; let i = index"><app-form-group [formGroup]="child"></app-form-group></ng-容器>
是的,是一种管理 FormArray 的不同方式,但请记住,formArray 只是一个特殊的"FormGroup.
更新有了这个想法,我们要更深入,在html中只使用[formControl],因此,我们需要将控件"作为变量传递.请参阅stackblitz>
表单归档视图就像
更新 2 简化了表单的创建,请参阅 stackblitz
ngOnInit() {let group = new FormGroup({});this.formFields.forEach(element => {让 formItem = this.createFormGroup(element);group.addControl(element.id, formItem);});this.myForm = 组;}私有 createFormGroup(formItem: FormModel) {if (formItem.type=="group"){if (formItem.isArray && formItem.children.length<formItem.minQtd){const add={...formItem.children[0]}//在这里我们可以清理"值while (formItem.children.length<formItem.minQtd)formItem.children.push(添加)}let group:FormGroup=new FormGroup({});让控件:any[]=[]formItem.children.forEach(元素=>{让 item=this.createFormGroup(element);如果(formItem.isArray)控制推(项目);别的group.addControl(element.id, item);})如果(!formItem.isArray)返回组;返回新的 FormArray(控件)}如果(formItem.type==控制")返回新的 FormControl();}
I am trying to implement a feature on my angular app where the users will be able to create their own forms (selecting fields/validation/etc). Once they create the form, I'll store it's JSON structure on the DB for use later:
export interface FormModel {
id: string;
name: string;
type: 'group' | 'control';
children: FormModel[];
isArray: boolean;
}
A sample structure is this:
[{
id: 'users',
name: 'Users',
type: 'group',
isArray: true,
children: [
{
id: "user",
name: "User",
type: 'group',
isArray: false,
children: [
{
id: "name",
name: "Name",
type: 'control',
children: null,
isArray: false
},
{
id: "age",
name: "Age",
type: 'control',
children: null,
isArray: false
}
]
},
{
id: "user",
name: "User",
type: 'group',
isArray: false,
children: [
{
id: "name",
name: "Name",
type: 'control',
children: null,
isArray: false,
},
{
id: "age",
name: "Age",
type: 'control',
children: null,
isArray: false
}
]
}
]
}, {
id: 'comments',
name: 'Comments',
type: 'control',
children: null,
isArray: false
}
];
After creating the reactive form based on the JSON loaded from the DB, I'm having difficulties creating the respective html since it has recursion.
After many attempts, I managed to get to the following, where it generates a HTML similar to what I understand should be needed:
<div formGroupName="users">
<div formArrayName="0">
<div formGroupName="user">
<input type="text" formControlName="name">
<input type="text" formControlName="age">
</div>
</div>
<div formArrayName="0">
<div formGroupName="user">
<input type="text" formControlName="name">
<input type="text" formControlName="age">
</div>
</div>
</div>
The template I've used is the following:
<form name="myForm" [formGroup]="myForm" fxLayout="column" fxFlex>
<div formGroupName="variables">
<ng-template #recursiveList let-controls let-prefix="prefix">
<ng-container *ngFor="let item of controls; let i = index;">
<input type="text" [formControlName]="item.id" *ngIf="(item?.children?.length > 0) == false">
<div *ngIf="item?.children?.length > 0 && item.isArray" [formArrayName]="item.id">
<ng-container
*ngTemplateOutlet="recursiveArray; context:{ $implicit: item.children, prefix: item.isArray }">
</ng-container>
</div>
<div *ngIf="item?.children?.length > 0 && !item.isArray" [formGroupName]="item.id">
<ng-container
*ngTemplateOutlet="recursiveList; context:{ $implicit: item.children, prefix: item.isArray }">
</ng-container>
</div>
</ng-container>
</ng-template>
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: formFields, prefix: '' }">
</ng-container>
<ng-template #recursiveArray let-controls let-prefix="prefix">
<ng-container *ngFor="let item of controls; let i = index;">
<div [formGroupName]="i">
<input type="text" [formControlName]="item.id" *ngIf="(item?.children?.length > 0) == false">
<div *ngIf="item?.children?.length > 0 && item.isArray" [formArrayName]="item.id">
<ng-container
*ngTemplateOutlet="recursiveArray; context:{ $implicit: item.children, prefix: item.isArray }">
</ng-container>
</div>
<div *ngIf="item?.children?.length > 0 && !item.isArray" [formGroupName]="item.id">
<ng-container
*ngTemplateOutlet="recursiveList; context:{ $implicit: item.children, prefix: item.isArray }">
</ng-container>
</div>
</div>
</ng-container>
</ng-template>
</div>
</form>
It seems to me that it is right, but I keep getting errors:
ERROR
Error: Cannot find control with path: 'variables -> 0'
ERROR
Error: Cannot find control with path: 'variables -> 0 -> user'
I have created a stackblitz with the sample:
https://stackblitz.com/edit/angular-mtbien
Could you guys help me identify the problem? I've been working on this for 2 days without any success :(
Thanks!
解决方案
As Ersenkoening say, for work with FormsGroup and Form Arrays you can use the "controls", directly. Use FormArrayName, Form Group, etc, can be a real headache.
See that the form-array.component.html of Ersenkoening can be coded more simple like
<div [formGroup]="formArray">
<ng-container *ngFor="let child of formArray.controls; let i = index">
<app-form-group [formGroup]="child"></app-form-group>
</ng-container>
</div>
Yes is a different way to mannage a FormArray but remember that a formArray it's only a "especial" FormGroup.
Update
With this idea, we are going to go more deeper, in the html only use [formControl], so, we need pass the "control" as a variable. See stackblitz
The form-filed-view is like
<form name="myForm" [formGroup]="myForm" fxLayout="column" fxFlex>
<div *ngFor="let item of formFields;let i=index">
{{item.id}}
<ng-container *ngTemplateOutlet="recursiveList; context:{
$implicit: formFields[i],
<!--see how pass the control of myForm--->
control:myForm.get(item.id) }">
</ng-container>
</div>
<ng-template #recursiveList let-item let-control="control">
<div *ngIf="!item.children">
{{item.id}}<input [formControl]="control">
</div>
<div *ngIf="item.children">
<div *ngIf="!item.isArray">
<div *ngFor="let children of item.children">
<ng-container *ngTemplateOutlet="recursiveList; context:{
$implicit:children,
<!--see how pass the control of a formGroup--->
control:control.get(children.id)}">
</ng-container>
</div>
</div>
<div *ngIf="item.isArray">
<div *ngFor="let children of item.children;let i=index">
<ng-container *ngTemplateOutlet="recursiveList; context:{
$implicit:children,
<!--see how pass the control of a formArray--->
control:control.at(i)}">
</ng-container>
</div>
</div>
</div>
</ng-template>
</form>
<pre>
{{myForm?.value|json}}
</pre>
Update 2 simplify the creation of the form, see stackblitz
ngOnInit() {
let group = new FormGroup({});
this.formFields.forEach(element => {
let formItem = this.createFormGroup(element);
group.addControl(element.id, formItem);
});
this.myForm = group;
}
private createFormGroup(formItem: FormModel) {
if (formItem.type=="group")
{
if (formItem.isArray && formItem.children.length<formItem.minQtd)
{
const add={...formItem.children[0]}
//here we can "clean" the value
while (formItem.children.length<formItem.minQtd)
formItem.children.push(add)
}
let group:FormGroup=new FormGroup({});
let controls:any[]=[]
formItem.children.forEach(element=>{
let item=this.createFormGroup(element);
if (formItem.isArray)
controls.push(item);
else
group.addControl(element.id, item);
})
if (!formItem.isArray)
return group;
return new FormArray(controls)
}
if (formItem.type=="control")
return new FormControl();
}
这篇关于Angular Reative Forms >用户自定义表单错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文