如何根据 Angular 响应式表单重新分配嵌套数组键?

How to reassign the nested array keys based on Angular Reactive Forms?

我正在努力为 Angular 响应式表单重新创建嵌套数组。

现有嵌套数组。

nestedArray = [{
    id:'abc',
    required:true,
    children:[{
        id:"bcd",
        parentId:"abc",
        required:true,
        children:[{
            id:"cde",
            parentId:"bcd",
            required:false,
            children:[{
                id:"def",
                parentId:"cde",
                required:true,
                children:[{
                    id:"efg",
                    parentId:"def",
                    required:false,                        
                }]
            },
            {
                id: "xyz",
                parentId: "cde",
                required: true,
            }]
        }]
    }]
}]

Angular 反应形式重新创建此数组

nestedArray= this.fb.group({
    abc: [''],
    bcd: this.fb.group({
      cde: [''],
      efg: [''],
    }),
  });

以上数组不正确,正在寻找以 Angular 反应形式创建子项的正确方法。

谢谢

下面只是一个伪代码,但您需要迭代并创建最终的键值对象以获得类似的结构...

无论如何,有一些工具可以解决类似的问题,考虑一下:https://jsonforms.io/ - 我会先考虑这些。

function patch (array: any[]): any { 
  let res: any = {};    
  for (let a of array) {
      res[a.id] = a;
      if (a.children && a.children.length) res[a.id]['children'] = patch(a.children)
  }

  return res;    
}

您需要创建一个递归函数 return 一个 FormControl 或一个 FormGroup

  form = new FormArray(this.nestedArray.map(x=>{
    const group=new FormGroup({})
    group.addControl(x.id,this.getGroup(x))
    return group
    }));

  getGroup(data: any) {
    if (!data.children)
      return new FormControl()
    const group = new FormGroup({});
    if (data.children) {
      
      data.children.forEach(x=>{
        group.addControl(x.id,this.getGroup(x))
      })
    }
    return group;
  }

stackblitz

Update 确实答案是错误的,因为我们没有对“parents”的表单控制。函数必须像

  form = new FormArray(this.nestedArray.map(x=>this.getGroup(x)))
  getGroup(data: any) {
    if (!data.children)
    { 
      return new FormControl)
    }
    const group = new FormGroup({});
    group.addControl(data.id,new FormControl())
    if (data.children) {
      
      data.children.forEach(x=>{
        group.addControl(x.id,this.getGroup(x))
      })
    }
    return group;
  }

嗯,问题是如何控制这种疯狂的形式。我们可以尝试创建一个“递归模板”,但我认为另一种方法更好。假设您有一组元素,每个元素都具有三个属性:“索引”、“标签”和“控件”。而control是对我们窗体的FormControl的引用。然后我们可以构造一个 .html like

<div *ngFor="let item of controls">
    <span [style.margin-left]="item.index*10+'px'">{{item.label}}</span>
    <input [formControl]="item.control">
    <span *ngIf="item.control.errors?.required">*</span>
</div>

容易不?直接使用 [formControl]item.control.errorsitem.control.touched

嗯,为此先声明一个空数组

  controls:any[]=[];

并更改功能,因此我们分两步添加组:1.-创建 formControl,2.-添加到组,第三步是将 object 与 {label ,控制和“指数”}。好吧,当我们有一个递归函数想知道递归的“索引”时,这很典型。

  //we pass as index 0 at first
  form = new FormArray(this.nestedArray.map(x=>this.getGroup(x,0)))
  getGroup(data: any,index:number) {
    if (!data.children)
    { 
      //create the control
      const control=new FormControl('',data.required?Validators.required:null)

      //add to the array this.controls
      this.controls.push({control:control,label:data.id,index:index})

      //return control
      return control
    }
    const group = new FormGroup({});
    index++
    //create the control
    const control=new FormControl('',data.required?Validators.required:null)

    //add to the array this.controls
    this.controls.push({control:control,label:data.id,index:index})

    //add the control to the group
    group.addControl(data.id,control)

    if (data.children) {
      data.children.forEach(x=>{
        group.addControl(x.id,this.getGroup(x,index++))
      })
    }
    return group;
  }

好吧,在 stackblitz 中,将 属性“值”添加到我们的复合体 object,以展示如何做到这一点,我们将“id”用作“标签”-perhafs复杂 object 需要一个新的 属性 标签-