角的嵌套表单数组 [英] Nested form array in angular

查看:87
本文介绍了角的嵌套表单数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用反应式表单进行角度应用程序,其中我制作了一个嵌套的表单数组,该数组将在单击按钮时嵌套.

I am making angular application with reactive form, where i have made a nested form array which will get nested on button click.

干净的工作示例 https://stackblitz.com/edit/angular-thhczx ,它具有静态输入,因此在单击Add new template时,它将添加另一个嵌套部分,对于Add new property,它将生成另一个属性数组.

A clean working example https://stackblitz.com/edit/angular-thhczx , it has static inputs and hence on click over Add new template, it will add a another nested part and for Add new property, it will generate another property array..

所以您正确理解了上面的工作示例概念?

So you had got the above working example concept right??

我想使用相同的json,但不希望使用添加按钮和下拉.

I would like to have the same json but not with add button and with dropdown.

下拉列表:

<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创建了 stackblitz 链接. com/edit/angular-1sg5cv

Also made a stackblitz link for the above https://stackblitz.com/edit/angular-1sg5cv

如果我从下拉菜单中选择选项template onetemplate two(因为选择框为多选),则我期望输出

Here if i select the option template one and template two (as the selectbox is multi select) from the dropdown then i am expecting the output as,

"template_details" : [
    { "template_name": "Template One",
      "template_data" : [{"property_one": "", "property_two":""}]
    },
    { "template_name": "Template Two",
      "template_data" : [{"property_three": "", "property_four":"", 
                            "property_five":""}]
    }
    ]

如果单击模板1和2的两个选项,您将看到分别得到twothree输入框...

If you click over the two options of template one and two you can see that you will get two and three input boxes respectively...

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

I wish to generate the input boxes with property names automatically under each template on selection of dropdown values..

因此,只需转换下拉演示,就像

So in simple need to convert dropdown demo as like the static inputs with add button with the same nested json structure.

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

I kindly request angular experts to help me in generation of input boxes based on property names for the selected template's..

我在无法获得解决方案的过程中做到了最好,请帮助我根据下拉列表的选择来形成嵌套数组json.

I did my level best in it unable to get the solution please help me to form nested array json on based on selection of dropdown..

推荐答案

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

@Undefined, you need two different jobs

  1. 创建一个formGroup
  2. 显示管理formGroup的输入

第一部分是画架.逐步进行,如果您选择模板一,则需要类似

the first part is the easer. Go step by step, if you select template one, you need some like

this.fb.group({
    template_name:"template one",
    template_data:this.fb.array([
          this.fb.group({
             property_one:'',
             property_two:''
          })
    ])
})

,但是您想做些灵巧的事,因此,使函数能够接收对象并返回FormGroup.由于您只需要模板和子项的值",因此您的功能可以像

but you want to do the things dinamically, so, make a function that receive an object and return a FormGroup. As you only need the "value" of the template and the childs, your function can be like

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

So yet we can create a formGroup for the differents templates and join in a 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);
    })
}

请注意,如果我们所有的模板子级都位于属性子级"下(第一个不是templateOneChild,第二个不是templateOneChild ...),我们的函数将变为

See that if all ours children of templates was under a property "children" (not templateOneChild for the first, templateTwoChild for the seconds...) our function becomes 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);
    })
}

好了,您已经创建了表单",现在该展示它了.形式就像

Well you have the "form" created, now is time to show it. The form is like

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

Yes, we have a problem, we don't know the "formControlName" of the inner formArray. One solution is have a variable "controlsName" that will be an array of array, so, if e.g. we choose 1 and 3 template our controlsName was like

controlsName=[
   ["property_one","property_two"],
   ["property_six",property_seven"]
]

好吧,再次创建一个函数,该函数返回带有属性名称的字符串数组.这是我们createFormGroup的简单版本,可以接收子项"并返回字符串数组.

Well, again make a function that return an array of strings with the names of the properties. it's a simply version of our createFormGroup, receive "children" and return an array of strings.

getControlNames(children:any[]):string[]
{
     let controlNames:string[]=children.map(x=>x.property_name);
     return controlNames;
}

好吧,在changeEvent中,我们在调用createFormGroup之后调用了此函数

Well, in changeEvent we call to this function after call to 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 ="??????????" >通过

After this, replace the < input formControlName="??????????" > by

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

请注意我们使用[formControlName](而不是formControlName),因为它是一个计算表达式.

See that we use [formControlName] (not formControlName) because is an evaluated expression.

请参见stackblitz 此处

See the stackblitz here

这篇关于角的嵌套表单数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆