带有动态递归模板的 ReactiveForms

Dal*_*rzo 8 angular angular-reactive-forms

这是我的问题。

在线问题示例

我有一个需要转换为表单的动态 JSON。因此,我使用了响应式表单,并通过检查 JSON 的所有属性,以这种方式创建了 FormGroup 或 FormControl:

sampleJson ={prop1:"value1", prop2: "value2",...}

...

  myForm: FormGroup;
  myKeys=[];
    ...

  ngOnInit() {
    this.myForm = this.getFormGroupControls(this.sampleJson, this.myKeys);

  }

getFormGroupControls(json:any,keys): FormGroup{
    let controls = {};
    let value = {};

    for (let key in json) {
      if (json.hasOwnProperty(key)) {

        value = json[key];
        if (value instanceof Object && value.constructor === Object) {

          keys.push({"key":key,children:[]});
          controls[key] = this.getFormGroupControls(value,keys[keys.length-1].children);
        } else {

          keys.push({"key":key,children:[]});
          controls[key] = new FormControl(value);

        }
      }
    }

    return new FormGroup(controls);
  }
Run Code Online (Sandbox Code Playgroud)

这样做之后,我使用递归模板来构建表单,如果我不使用递归模板,我会让表单工作。但是使用递归模板我收到错误:

<form [formGroup]="myForm">

  <div class="form-group">


    <ng-template #nodeTemplateRef let-node>

      <div class="node">
        <div  *ngIf="node.children.length">
          {{"section [formGroupName]="}} {{ getNodeKey(node) }}
          <section style="display:block;margin:20px;border:solid 1px blue;padding-bottom: 5px;"
            [formGroupName]="getNodeKey(node)" >
            <h1>{{ node.key }}</h1>
            <ng-template
              ngFor
              [ngForOf]="node.children"
              [ngForTemplate]="nodeTemplateRef">
            </ng-template>
          </section>
          {{"end of section"}}
        </div>
        <div  *ngIf="!node.children.length">
          <label [for]="node.key">{{node.key}}</label>&nbsp;
          <input  type="text" [id]="node.key"
                  class="form-control">
        </div>
      </div>

    </ng-template>

    <ng-template *ngFor="let myKey of myKeys"
                 [ngTemplateOutlet]="nodeTemplateRef"
                 [ngTemplateOutletContext]="{ $implicit: myKey   }">
    </ng-template>

  </div>
Run Code Online (Sandbox Code Playgroud)

PreviousComponent.html:25 ERROR 错误:找不到名称为“road”的控件

这对应于这个示例 JSON:

"address": {
        "town": "townington",
        "county": "Shireshire",

        "road": {
          "number": "1",
          "street": "the street"
        }
Run Code Online (Sandbox Code Playgroud)

I have 正在显示,所以我知道元素在那里。我错过了什么?

Pet*_*nov 10

您当前代码的问题似乎是 ng-template parent 是您的应用程序组件,因此它没有考虑您定义的顶级模板中的其他 formGroupNames,并且始终在根 FormGroup 中查找。

模板中似乎也不支持完整的组名/控件名称(例如 cant use formGroupName="address.road"

如果出于某种原因需要 formGroups - 您可以将它们在上下文中传递给模板。或者您可以直接处理 formControls:

  • formGroupName从模板中删除所有内容
  • store fullPath:(keys.push({"key":key,children:[], fullKey: parent ? parent.fullKey + '.' + key: key});你也可以存储FormControl实例本身。)
  • 并使用它: <input type="text" [formControl]="myForm.get(node.fullKey)"

Stackblitz 示例


小智 2

或者,如果您仍然需要表单组/控件层次结构,您可以通过递归传递来使用 formGroup 和 formControl 指令(而不是 formGroupName 和 formControlName)

Stackblit 链接

注意:这里有同样的问题:Recursive ReactiveForm 无法在模板内找到 formGroups