我正在使用响应式(Reactive)表单制作 Angular 应用程序,其中我制作了一个嵌套表单数组,它将在单击按钮时嵌套。
一个干净的工作示例 https://stackblitz.com/edit/angular-thhczx ,它具有静态输入,因此单击 Add new template
,它将添加另一个嵌套部分,对于 Add new property
,它将生成另一个属性数组..
所以您已经正确理解了上述工作示例的概念?
我想要相同的 json,但不使用添加按钮和 下拉。
下拉菜单的 HTML:
<select multiple [(ngModel)]="selectItems" (change)="changeEvent($event)">
<option *ngFor="let template of templates" [value]="template.key">{{template.value}}</option>
</select>
{{selectItems|json}}
<form [formGroup]="form">
<div *ngFor="let item of array">
{{item.value}} is the parent
<div *ngFor="let child of item.templateChild">
{{child.property_name}}
<input type="text" [value]="child.property_name">
</div>
<br><br><br>
</div>
</form>
<br><br><br>
{{form.value|json}}
模板数组:为下拉列表提供值
templates = [
{
key: 1, value: "Template one",
templateOneChild: [
{ property_name: "Property one" },
{ property_name: "Property two" }
]
},
{
key: 2, value: "Template two",
templateTwoChild: [
{ property_name: "Property three" },
{ property_name: "Property four" },
{ property_name: "Property five" }
]
},
{
key: 3, value: "Template three",
templateThreeChild: [
{ property_name: "Property six" },
{ property_name: "Property seven" }
]
}
]
还为上述内容创建了一个stackblitz链接https://stackblitz.com/edit/angular-1sg5cv
如果我选择选项 template one
和template two
(因为选择框是多项选择)从下拉列表中,那么我期望输出为,
"template_details" : [
{ "template_name": "Template One",
"template_data" : [{"property_one": "", "property_two":""}]
},
{ "template_name": "Template Two",
"template_data" : [{"property_three": "", "property_four":"",
"property_five":""}]
}
]
如果您单击模板一和模板二的两个选项,您可以看到您将获得 two
和three
分别输入框...
我希望在选择下拉值时在每个模板下自动生成带有属性名称的输入框。
所以简单地需要转换dropdown demo就像 static inputs with add button具有相同的嵌套 json 结构。
我恳请 Angular 专家帮助我根据所选模板的属性名称生成输入框..
我尽了最大努力,无法获得解决方案,请帮助我根据下拉列表的选择形成嵌套数组 json..
最佳答案
@Undefined,你需要两个不同的工作
- 创建表单组
- 显示管理 formGroup 的输入
第一部分是更简单的部分。一步一步来,如果你选择模板一,你需要一些像
this.fb.group({
template_name:"template one",
template_data:this.fb.array([
this.fb.group({
property_one:'',
property_two:''
})
])
})
但是您想要动态地执行这些操作,因此,创建一个接收对象并返回 FormGroup 的函数。由于您只需要模板和子模板的“值”,因此您的函数可以是这样的
createFormGroup(value:string,children:any[]):FormGroup
{
/*e.g. for template one, you send
value: "Template one",
children: [
{ property_name: "Property one" },
{ property_name: "Property two" }
]
*/
let controls:FormGroup[]=children.map(
(x:any)=>this.fb.group({
[x.property_name]:''
})
)
return this.fb.group({
template_name:value,
template_data:this.fb.array(controls)
})
}
所以我们可以为不同的模板创建一个 formGroup 并加入 FormArray
changeEvent(e) {
let arrayControls:FormGroup[] = [];
//in this.selectItems we have, e.g. [1,3]
for (let select of this.selectItems) {
//search the template, select will be e.g. 1,3
let template:any=this.templates.find(x=>x.key==select);
switch (+select) {
case 1:
arrayControls.push(this.createFormGroup(template.value,template.templateOneChild));
break;
case 2:
arrayControls.push(this.createFormGroup(template.value,template.templateTwoChild));
break;
case 3:
arrayControls.push(this.createFormGroup(template.value,template.templateThreeChild));
break;
}
}
this.form=this.fb.group({
template_details:this.fb.array(arrayControls);
})
}
请注意,如果模板的所有子级都位于属性“children”下(第一个不是 templateOneChild,第二个是 templateTwoChild...),我们的函数将变为
changeEvent(e) {
let arrayControls:FormGroup[] = [];
//in this.selectItems we have, e.g. [1,3]
for (let select of this.selectItems) {
//search the template, select will be e.g. 1,3
let template:any=this.templates.find(x=>x.key==select);
arrayControls.push(this.createFormGroup(template.value,template.children));
}
this.form=this.fb.group({
template_details:this.array(arrayControls);
})
}
好了,您已经创建了“表单”,现在是时候展示它了。形式就像
<div *ngIf="form">
<form [formGroup]="form">
<div formArrayName="template_details">
<div *ngFor="let item of details.controls;let i=index" [formGroupName]="i">
<input formControlName="template_name">
<div formArrayName="template_data">
<div *ngFor="let child of item.get('template_data').controls;let j=index" [formGroupName]="j">
<input formControlName="??????????">
</div>
</div>
</div>
</div>
</form>
</div>
是的,我们有一个问题,我们不知道内部 formArray 的“formControlName”。一种解决方案是使用一个变量“controlsName”,它将是一个数组的数组,因此,如果例如我们选择 1 和 3 模板,我们的控件名称如下
controlsName=[
["property_one","property_two"],
["property_six",property_seven"]
]
好吧,再次创建一个函数,返回一个包含属性名称的字符串数组。它是 createFormGroup 的简单版本,接收“children”并返回字符串数组。
getControlNames(children:any[]):string[]
{
let controlNames:string[]=children.map(x=>x.property_name);
return controlNames;
}
好吧,在changeEvent中,我们在调用createFormGroup后调用这个函数
changeEvent(e) {
let arrayControls:FormGroup[] = [];
let controlsName:string[] = []; //<--add this line
for (let select of this.selectItems) {
let template:any=this.templates.find(x=>x.key==select);
switch (+select) {
case 1:
arrayControls.push(this.createFormGroup(template.value,template.templateOneChild));
controlsName.push(this.getControlNames(template.templateOneChild)); //<--and this
break;
... idem with case 2 and case 3...
}
}
this.controlsName=controlsName; //<--give value to name first
//then create the form
this.form=this.fb.group({
template_details:this.fb.array(arrayControls);
})
在此之后,替换 < input formControlName="??????????"> 通过
<input [formControlName]="controlsName[i][j]">
请注意,我们使用 [formControlName](而不是 formControlName),因为 是一个计算表达式。
查看 stackblitz here
关于javascript - Angular 中的嵌套形式数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53538849/