角深层嵌套反应式窗体:在嵌套FormArray上找不到带有路径的控件 [英] Angular Deeply Nested Reactive Form: Cannot find control with path on nested FormArray

查看:98
本文介绍了角深层嵌套反应式窗体:在嵌套FormArray上找不到带有路径的控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个嵌套的动态Form,其中用户有一个组,然后可以在该组中嵌套条件,或者在group FormArray中嵌套新的其他组对象.这是基本UI的外观.请注意,并非所有部分都可以正常工作,但是现在,我正在尝试添加一个嵌套组.嵌套组适用于FormBuilder,但是会出现错误,并且无法在UI上正确显示.错误是:ERROR Error: Cannot find control with path: 'statement -> groups -> 0 -> groups -> conditions'.在继续之前,可以在 HERE

I am building a nested, dynamic Form where the User has a group, and then can nest conditions within that group, or new additional group objects within a group FormArray. Here is what the basic UI looks like. Note, not all the pieces are working, but for now I am trying to add a nested group. A nested group will work for the FormBuilder, but it gives an error and does not show correctly on the UI. The error is: ERROR Error: Cannot find control with path: 'statement -> groups -> 0 -> groups -> conditions' . Before going further, the StackBlitz can be found HERE

表单对象看起来像这样:

The form object looks like this:

{
  "statement": {
    "groups": [
      {
        "conjunctor": null,
        "conditions": [
          {
            "variable": ""
          }
        ],
        "groups": []
      }
    ]
  }
}

statement → groups → groups内,用户可以推动将包含组"对象的其他FormGroup:

Within the statement → groups → groups the user is able to push an additional FormGroup that will contain a "groups" object:

 {
 "conjunctor": null,
   "conditions": [
     {
       "variable": ""
     }
    ],
   "groups": []
 }

从长远来看,我希望能够推送更多的组并进一步嵌套此Form,但是现在,我正在尝试使其在UI上正常工作. HTML如下所示,并且在此StackBlitz中 .我继续收到错误: ERROR Error: Cannot find control with path: 'statement -> groups -> 0 -> groups -> conditions',并基于几个S.O.例如,我认识到此错误是由于我的HTML嵌套方式以及FormGroups和FormArrays引起的,其中肯定有问题.但是,我似乎无法使其工作以嵌套和显示嵌套组. 这是我尝试过的一些方法:

Long term, I expect to be able to push additional groups and further nest this Form, but for now, I am trying to get it to work on the UI. The HTML is as shown below and in this StackBlitz. I continue to get the error: ERROR Error: Cannot find control with path: 'statement -> groups -> 0 -> groups -> conditions' , and based off several S.O. examples, I recognize that this error is due to the way my HTML is nested and the FormGroups and FormArrays, there must be an issue within it. However, I cannot seem to get it to work in order to nest and display a nested group. Here are some approaches I have tried:

Angular FormArray:找不到带有路径的控件

角度:找不到具有以下路径的控件:'variable- > 0-> id'

Angular 7和表单数组错误,找不到具有路径的控件

错误错误:找不到具有路径的控件

作为一个旁注,我不确定这是否是实现嵌套可重用组件的最佳方法,但是我希望一旦停止出错就对此做进一步研究.

As a side-note, I'm not sure if this is even the best approach to implementing a nested reusable component, but I expect to research this further once I stop getting errors.

<form [formGroup]="form">
  <div formArrayName="statement">
    <div formArrayName="groups">
      <div *ngFor="let group of form.get('statement.groups')['controls']; let i = index">
        <fieldset>
          <legend>Group {{ i + 1 }}:</legend>
          <div [formGroupName]="i">
            <span style="float: right;">
              <button type="button" style="float: right; cursor: pointer; margin-left: 5px;" (click)="deleteGroup(i)">
                delete group
              </button>
              <button type="button" style="cursor: pointer; margin-left: 5px;" (click)="addNestedGroup(i)">
                add nested group
              </button>
              <button
                type="button"
                style="cursor: pointer; margin-left: 5px;"
                (click)="addNewCondition(group.controls.conditions)"
              >
                add condition
              </button>
            </span>
            <div formArrayName="conditions">
              <div *ngFor="let condition of group.get('conditions')['controls']; let j = index">
                <fieldset>
                  <legend>Condition {{ j + 1 }}</legend>
                  <div [formGroupName]="j">
                    <input style="vertical-align: middle;" type="text" formControlName="variable" />
                    <button
                      style="float: right; margin-bottom: 5px;"
                      (click)="deleteCondition(group.controls.conditions, j)"
                    >
                      delete condition
                    </button>
                  </div>
                </fieldset>
              </div>
            </div>
            <ng-container>
              <div formArrayName="groups">
                <div *ngFor="let num of group.get('groups').value; let idx = index">
                  <fieldset>
                    <legend>Group {{ 2 }}:</legend>
                    <span style="float: right;">
                      <button
                        type="button"
                        style="float: right; cursor: pointer; margin-left: 5px;"
                        (click)="deleteGroup(0)"
                      >
                        delete group
                      </button>
                      <button type="button" style="cursor: pointer; margin-left: 5px;" (click)="addNestedGroup(0)">
                        add nested group
                      </button>
                      <button
                        type="button"
                        style="cursor: pointer; margin-left: 5px;"
                        (click)="addNewCondition(num.conditions)"
                      >
                        add condition
                      </button>
                    </span>
                    <div formArrayName="conditions">
                      <div *ngFor="cond; of: group.controls; let k = index">
                        <fieldset>
                          <legend>Condition {{ k + 1 }}</legend>
                          <div [formGroupName]="k">
                            <input style="vertical-align: middle;" type="text" formControlName="variable" />
                            <button
                              style="float: right; margin-bottom: 5px;"
                              (click)="deleteCondition(group.controls.conditions, k)"
                            >
                              delete condition
                            </button>
                          </div>
                        </fieldset>
                      </div>
                    </div>
                  </fieldset>
                </div>
              </div>
            </ng-container>
          </div>
        </fieldset>
      </div>
    </div>
  </div>
</form>

推荐答案

我在

I've written a post at dev.to after writing this answer. Take a look.

您要处理的是复杂表格.它是嵌套的,并且是递归的(因为您有成组的组).我建议您将其拆分为更多组件.这样,您无论出于任何原因重新访问整个表格,都将变得更加容易.并且,作为一种非常受欢迎的樱桃蛋糕",您将避免使用用于访问控件的深层嵌套的对象路径(这可能会让人不知所措,因为您始终以动态方式嵌套动态表单).

You're dealing with a complex form. It's nested and it's recursive (as you have groups in groups). I suggest you split it into more components. By doing that, you'll make it easier to have a big picture of the whole form whenever you revisit it for any reason. And, as a very welcome cherry-on-the-cake, you will avoid the deeply nested object paths you're using to access your controls (this can be overwhelming as you keep nesting dynamic forms the way you're doing).

我要说的是,该错误很可能是由于您用于访问表单部件的深层对象路径中的一些愚蠢错误造成的.在处理这种复杂的嵌套形式时,通常不值得花费精力来解决与错误的对象路径有关的最终问题:对其进行重构以得到结构更整洁的组件.

What I'm trying to say is that the error is likely caused by some silly mistake in the deep object paths you use to get access to the form parts. When dealing with this kind of complex nested form, it usually isn't worth the effort to fix eventual issues related to wrong object paths: refactor it to get a more clean-structured component.

我强烈建议您执行以下将要描述的两件事(另请参阅此 Stackblitz演示).我在该演示中所做的是对表单的完整重构,我决定不将所有代码粘贴到此处,因为它太长,难以阅读,并且无论如何您都无法执行它.因此,这将毫无意义.只需转到 Stackblitz演示,然后在此处进行尝试.

I strongly suggest you do the two things I'll describe below (also, take a look at this Stackblitz demo). What I did in that demo is a complete refactor of your form and I decided not to paste all the code here because it would be excessively long, hard to read, and you wouldn't be able to execute it anyway. So it would be pointless. Just go to the Stackblitz demo and try it there.

您的表单有一个非常特殊的方面:它是递归的.因此,如果我们不尝试在递归自然流中划船,一切都会变得更加容易.

Your form has a very peculiar aspect: it's recursive. So everything is gonna be easier if we don't try to row the boat against its recursive nature stream.

我向您保证,我在该代码中没有做任何特别的事情,只是以下两个步骤:

I assure you I did nothing special in that code but just these two steps:

我们称之为GroupFormComponent.在这里不太常见的一件事是,在该组件的模板中,您将拥有...另一个GroupFormComponent.是的,您可以将角度分量递归地埋在其内部.

Let's call it GroupFormComponent. The one thing that's not so common here is that, in the template of this component, you're gonna have... another GroupFormComponent. Yes, you can bury an angular component inside itself recursively.

@Component({
  selector: 'group-form',
  template: `
    ...
    <!-- here you nest another instance of this component -->
    <group-form *ngIf="nestCondition"></group-form>
    ...
  `,
})
export class GroupFormComponent {...}

上面的代码片段有助于说明我的建议(这种结构显示了基于角度组件的特性可以走多远=>它功能强大,不是吗?)

The above snippet helps to illustrate what I'm suggesting you do (this kind of structure shows how far you can go with angular component-based nature => it's powerful, isn't it?).

您可以(并且应该)将表单的某些部分分组为其他组件,以使其更易于整体理解.无需花费大量精力,我们就可以确定三个组成部分:

You can (and should) group some parts of your form into other components, to make it easier to be understood as a whole. Without any great mental effort, we can identify three components:

  • 主要形式,包含整体形式

  • The main form, containing the overall form

操作栏按钮

条件组件

将所有这些零件组装在一起时,您将得到:

When you assemble all these parts together, you'll get:

<main-form>
  <action-buttons></action-buttons>
  <condition></condition>
  <condition></condition>
  ...
  <condition></condition>

  <!-- The recursive part -->
  <main-form></main-form>
  <main-form></main-form>
  ...
  <main-form></main-form>
</main-form>

为使其更加简单,<condition><main-form>组件必须必须实现ControlValueAccessor接口,以允许它们以其他形式用作FormControl.

To make it even more simple, <condition> and <main-form> components must implement the ControlValueAccessor interface in order to allow them to be used as FormControl's in other forms.

具备所有这些功能之后,您将获得一个健壮,可维护且灵活的表单.

With all these this in place, you'll have a robust, maintainable, and flexible form.

下面的动画gif显示了它的工作原理.

The animated gif below shows it working.

这篇关于角深层嵌套反应式窗体:在嵌套FormArray上找不到带有路径的控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆