我正在用反应式表单制作角度应用程序,在那里我制作了一个嵌套的表单数组,点击按钮就会嵌套。
一个干净的工作示例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
输入框。。。
我希望在选择下拉值时,在每个模板下自动生成具有属性名称的输入框。。
因此,只需将下拉演示转换为具有相同嵌套json结构的带有添加按钮的静态输入。
我恳请角度专家帮助我根据所选模板的属性名称生成输入框。。
我已经尽了最大的努力,无法获得解决方案,请帮助我根据下拉列表的选择形成嵌套数组json。。
@未定义,您需要两个不同的作业
- 创建表单组
- 显示管理表单组的输入
第一部分是画架。循序渐进,如果你选择一个模板,你需要一些像
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>