以角度嵌套形式数组



我正在用反应式表单制作角度应用程序,在那里我制作了一个嵌套的表单数组,点击按钮就会嵌套。

一个干净的工作示例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 onetemplate 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":""}]
}
]

如果你点击模板一和模板二的两个选项,你可以看到你将分别得到twothree输入框。。。

我希望在选择下拉值时,在每个模板下自动生成具有属性名称的输入框。。

因此,只需将下拉演示转换为具有相同嵌套json结构的带有添加按钮的静态输入。

我恳请角度专家帮助我根据所选模板的属性名称生成输入框。。

我已经尽了最大的努力,无法获得解决方案,请帮助我根据下拉列表的选择形成嵌套数组json。。

@未定义,您需要两个不同的作业

  1. 创建表单组
  2. 显示管理表单组的输入

第一部分是画架。循序渐进,如果你选择一个模板,你需要一些像

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,第二个是templateWoChild…(,则我们的函数将变为

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就像

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

之后,将<通过输入formControlName=">

<input [formControlName]="controlsName[i][j]"> 

请注意,我们使用[formControlName](而不是formControlName(,因为它是一个已求值的表达式。

点击此处查看堆叠

我不确定你的问题。您希望使用json动态添加控件。

参考链接:https://angular.io/guide/dynamic-form

工作示例:https://stackblitz.com/edit/angular-srpk3w

用以下代码替换您的文件:

app.component.html

<select multiple [(ngModel)]="selectItems" (change)="changeEvent($event)">
<option *ngFor="let template of templates" [value]="template.key">{{template.value}}</option>
</select>
{{selectItems|json}}
<div *ngIf="form">
<form [formGroup]="form"> 
<div *ngFor="let item of array">
{{item.value}} is the parent
<div *ngFor="let child of item.templateChild; index as i">
{{child.property_name}}
<input type="text" formControlName="{{child.property_name.split(' ').join('_')}}"  [value]="child.property_name" >
</div> 
<br><br><br>
</div>
</form>
</div>
<br><br><br>
{{form.value|json}}

应用程序组件.ts

import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
array: any[] = [];
selectItems: any;
form: FormGroup;
templates = [
{
key: 1, value: "Template one",
templateChild: [
{ property_name: "Property one" },
{ property_name: "Property two" }
]
},
{
key: 2, value: "Template two",
templateChild: [
{ property_name: "Property three" },
{ property_name: "Property four" },
{ property_name: "Property five" }
]
},
{
key: 3, value: "Template three",
templateChild: [
{ property_name: "Property six" },
{ property_name: "Property seven" }
]
}
]

changeEvent(e) {
this.array = [];
for (let select of this.selectItems) {
this.array.push(this.templates[select-1])
this.form=this.getFormValue(this.array);
}     
}
getFormValue(array){
let group: any = {};
array.forEach(r=>{
r.templateChild.forEach((t,index)=>{
group[t.property_name.replace(/ /g, "_")]= new FormControl(t.property_name);
})
})
return new FormGroup(group);;
}
}

在ts 中尝试此操作

import { FormBuilder, FormGroup, Validators } from '@angular/forms';
constructor(private formBuilder: FormBuilder) {
this.myForm = this.formBuilder.group({
selectedItems: [[]],
itemQuestions: this.formBuilder.array([])
});
}itemQuestions: any[] = [
{ question: 'Question 1', options: ['Yes', 'No'] },
{ question: 'Question 2', options: ['Yes', 'No'] },
{ question: 'Question 3', options: ['Yes', 'No'] }
];
generateItemQuestions(): FormGroup[] {
const selectedItems = this.myForm.get('selectedItems').value;
return selectedItems.map((item: string) => {
return this.formBuilder.group({
item: [item],
answers: ['', Validators.required]
});
});
}
onSelectionChange() {
const itemQuestions = this.generateItemQuestions();
this.myForm.setControl('itemQuestions',               
this.formBuilder.array(itemQuestions));
}
onSubmit() {
if (this.myForm.valid) {
const formValue = this.myForm.value;
console.log(formValue);
// Perform necessary actions with the form data
} else {
// Form is invalid, display error messages or handle accordingly
}
}

在html 中

<form [formGroup]="myForm" (ngSubmit)="onSubmit()">
<ion-item>
<ion-label>Selected Items</ion-label>
<ion-select formControlName="selectedItems" multiple="true">
<ion-select-option value="Item 1">Item 1</ion-select-option>
<ion-select-option value="Item 2">Item 2</ion-select-option>
<!-- Add other options -->
</ion-select>
</ion-item>

<div formArrayName="itemQuestions">
<div *ngFor="let questionGroup of myForm.get('itemQuestions').controls; let i=index" [formGroupName]="i">
<div>
{{ questionGroup.get('item').value }}
</div>

<div *ngFor="let question of itemQuestions">
<div>{{ question.question }}</div>
<ion-radio-group formControlName="answers">
<ion-item>
<ion-label>Yes</ion-label>
<ion-radio value="Yes"></ion-radio>
</ion-item>
<ion-item>
<ion-label>No</ion-label>
<ion-radio value="No"></ion-radio>
</ion-item>
</ion-radio-group>
</div>
</div>
</div>

<ion-button type="submit">Submit</ion-button>
</form>

最新更新