【问题标题】:ReactiveForms with dynamic recursive templates具有动态递归模板的反应式表单
【发布时间】:2020-01-16 18:09:42
【问题描述】:

这是我的问题。

Online Example of the issue

我有一个动态 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);
  }

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

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

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

对应于这个示例 JSON:

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

        "road": {
          "number": "1",
          "street": "the street"
        }

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

【问题讨论】:

  • 我相信[formGroupName]="road" 不知道它嵌套在address 表单组下。它正在直接在根[formGroup]="myForm" 下寻找一个名为road 的表单组。如果您将road 表单组直接嵌套在myForm 下,您将看到该错误不再出现。
  • 在任何地方将 formGroupName 替换为 formGroup 可能会解决问题。但是您需要一种方法来为每个嵌套组获取正确的 FormGroup 实例。
  • 创建另一个错误> 无法在字符串“名称”上创建属性“验证器”
  • 动态 json 总是会返回一个已知的集合吗?这可能会改变,但我们可以意识到它们并有一些类型安全的东西?
  • 我想我要问的是:它是真正动态的还是只是oneOf 来自一组已知的可能条目,如namepersonaladdress

标签: angular angular-reactive-forms


【解决方案1】:

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

模板中似乎也不支持完整的组名/控件名(例如,不能使用formGroupName="address.road"

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

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

Stackblitz Example

【讨论】:

    【解决方案2】:

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

    Stackblits link

    注意:这里有同样的问题:Recursive ReactiveForm cannot find formGroups inside of template

    【讨论】:

    • 这个最终工作得更好,并且对我最初的目标需要的更改更少。这就是为什么我授予它响应,因为我认为它更准确
    猜你喜欢
    • 2020-05-13
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 2014-06-01
    • 2017-11-17
    • 1970-01-01
    • 2017-02-07
    • 1970-01-01
    相关资源
    最近更新 更多