代码之家  ›  专栏  ›  技术社区  ›  Maniraj Murugan

角网格中的嵌套形式数组

  •  0
  • Maniraj Murugan  · 技术社区  · 7 年前

    干净的 工作 https://stackblitz.com/edit/angular-thhczx ,它有静态输入,因此单击 Add new template ,它将添加另一个嵌套零件并用于 Add new property ,它将生成另一个属性数组。。

    因此,您正确地理解了上述工作示例概念??

    我希望使用相同的json,但不使用add按钮和 .

    下拉列表的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

    这里,如果我选择了这个选项 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 分别输入框。。。

    所以在简单的需要转换 dropdown demo 就像 static inputs with add button 使用相同的嵌套json结构。

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

    2 回复  |  直到 7 年前
        1
  •  3
  •   Eliseo    7 年前

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

    第一部分是画架。一步一步走,如果你选择模板一,你需要一些类似的

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

    但是您希望以友好的方式进行操作,因此,创建一个函数来接收一个对象并返回一个FormGroup。因为您只需要模板和child的“值”,所以您的函数可以是

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

    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…)下,则函数将变为

    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]="controlsName[i][j]"> 
    

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

    看《闪电战》 here

        2
  •  0
  •   Vignesh Pandi    7 年前

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

    https://stackblitz.com/edit/angular-srpk3w

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

    <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);;
    }
    }
    
    推荐文章