javascript Angular 中的嵌套窗体数组

nxowjjhe  于 2023-06-04  发布在  Java
关注(0)|答案(3)|浏览(293)

我正在使用React式表单制作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" }
      ]
    }
  ]

还为上面的https://stackblitz.com/edit/angular-1sg5cv做了stackblitz链接
在这里,如果我从下拉列表中选择选项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输入框。
我希望生成的属性名称输入框自动根据每个模板上的下拉值的选择。
因此,只需将dropdown demo转换为具有相同嵌套json结构的static inputs with add button
我恳请Angular Maven帮助我在输入框的基础上为选定的模板的属性名称生成。
我做了我的水平最好在它无法得到的解决方案,请帮助我形成嵌套数组JSON的基础上选择下拉菜单..

2izufjch

2izufjch1#

@未定义,需要两份不同的工作
1.创建表单组
1.显示管理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...),我们的函数就变成了in

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

在此之后,将替换< input formControlName="??????????" >为

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

请注意,我们使用[formControlName](而不是formControlName),因为它是一个求值表达式。
查看stackblitz here

ebdffaop

ebdffaop2#

我不太清楚你的问题。你想用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}}

app.component.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);;
}
}
tzxcd3kk

tzxcd3kk3#

在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>

相关问题