动态嵌套表单控件Angular 2

时间:2017-09-13 09:55:52

标签: angular angular2-forms angular2-formbuilder angular-forms

我的API响应就像

"groups": [{
          "group_name": "GRP1"
          "attributes": [{
                        "attribute_id": 1,
                        "attribute_name": "Frequency",
                        "value_reference": "tag"
                        }]
          },
          {
            "group_name": "GRP2"
           "attributes": [{
                        "attribute_id": 2,
                       "attribute_name": "Date",
                        "value_reference": "static",
                        "value_static_type": "date"
                      }]
              }]  

- 我如何在Angular 4中创建formConrol来显示像

这样的数据
GroupName  
   List of Group's Attribute  
GroupName
    List of Group's Attribute  

我的初始表单控件就像

this.editTemplateForm = this.fb.group({
            groups: this.fb.group({
                group_name: ['', Validators.required ],
                attributes : this.fb.group({
                    value_reference : []
                })
            }),
        });  

我不明白如何动态添加控件

1 个答案:

答案 0 :(得分:2)

如果您想要准确匹配您的API响应,那么此处的结构最终会相当复杂。由于到目前为止,每个attributes属性只有一个属性对象,因此您可以直接使attributes成为对象,而不是对象数组,这将简化以下代码。以下代码与您当前的API结构相匹配,可以在this working plunker播放。

要记住的一些事情:

  • FormGroup需要是最外层的表单对象,也可用于保存不确定数量的FormControl
  • 另一方面,
  • FormArray在控件数量不确定时非常有用,调用这些控件无关紧要。
  • 这就是为什么在下面,allGroups是一个包含最大组的数组,attributes是一个包含属性对象的数组,但这些属性对象本身就是组 - 因为我们希望能够根据API属性名称
  • 命名控件

此结构也很有可能完全 你正在寻找的东西(例如,你可能并不希望所有这些值都是可编辑的<input>字段),但它应该为您提供强有力的基础,以便了解如何根据更改的表单对象动态生成HTML。

import {Component} from '@angular/core';
import {FormGroup, FormControl, FormArray, FormBuilder} from '@angular/forms';

interface APIGroup {
    'group_name': string;
    'attributes': Array<GroupAttributes>
}
interface GroupAttributes {
    'attribute_id': number;
    'attribute_name': string;
    'value_reference': string;
    'value_static_type'?: string;
}

@Component({
  selector: 'app-child',
  template: `
    <div>
      <h3>I'm the Child component</h3>
    </div>
    <form [formGroup]="editTemplateForm">
        <div formArrayName="allGroups">
            <div *ngFor="let group of editTemplateForm.get('allGroups').controls; let i=index" [formGroupName]="i">
                <input formControlName="groupName" />
                <div formArrayName="attributes">
                    <div *ngFor="let attributeGroup of group.get('attributes').controls; let n=index" [formGroupName]="n">
                        <input *ngFor="let key of keysOfFormGroup(attributeGroup)" [formControlName]="key" />
                    </div>
                </div>
                <br/>
            </div>
        </div>
    </form>
    <pre style="background: #ddd">{{editTemplateForm.value | json}}</pre>
  `,
})
export class ChildComponent {
    constructor(
        private fb: FormBuilder
    ) { }

    sampleData: Array<APIGroup> = [
        {
            "group_name": "GRP1",
            "attributes": [{
                "attribute_id": 1,
                "attribute_name": "Frequency",
                "value_reference": "tag"
            }]
        },
        {
            "group_name": "GRP2",
            "attributes": [{
                "attribute_id": 2,
                "attribute_name": "Date",
                "value_reference": "static",
                "value_static_type": "date"
            }]
        }
    ]

    editTemplateForm: FormGroup;

    ngOnInit() {
        this.editTemplateForm = this.fb.group({
            allGroups: this.fb.array([])
        });

        // would call on a subscription to actual api data
        this.sampleData.forEach(group => {
            (<FormArray>this.editTemplateForm.get('allGroups'))
                .push(this.initGroup(group));            
        });
    }

    initGroup(apiGroup: APIGroup): FormGroup {
        let formGroup = this.fb.group({
            groupName: [apiGroup.group_name],
            attributes: this.fb.array([])
        });
        apiGroup.attributes.forEach(attributeGroup => {
            (<FormArray>formGroup.get('attributes'))
                .push(this.initAttributeGroup(attributeGroup));
        });
        return formGroup;
    }

    initAttributeGroup(attributes: GroupAttributes): FormGroup {
        let formGroup = this.fb.group({});
        Object.keys(attributes).forEach(name => {
            formGroup.addControl(name, new FormControl(attributes[name]));
        });
        return formGroup;
    }

    keysOfFormGroup(group: FormGroup): Array<string> {
        return Object.keys(group.controls);
    }
}