首页 > 解决方案 > 无法在递归角度表单上使用 ngIf 找到带有路径的控件

问题描述

这是下面代码的堆栈闪电战。我正在使用 FormArrays 和子组件制作一个相当复杂的深度嵌套的 Angular 表单。在大多数情况下,一切都按预期工作。group对象包含conjunctorconditions[]groups[]groups[]是一个嵌套组,可以无限嵌套包含相同的对象。

目前,您可以选择“添加组”、“添加嵌套组”、“添加条件”、“删除组”和“删除条件”,以便创建嵌套表单对象。为此,应用程序分为 3 个组件:

ng-containerAppComponent:用s保存主窗体并*ngFor遍历组

GroupControlComponent:保存 AppComponent 中每个项目的逻辑,并与 AppComponent 执行相同的操作,但用于条件和嵌套组

条件表单:保存条件项的逻辑

还有一个 ActionsButtonsBarComponent 来保存按钮以发出事件、添加和删除组和条件。

我试图在每第二组中做到这一点,Conjunctor 有一个输入。我根本不希望它在第一个实例上,因为我希望第一个始终为空。但是,在第 2 次及之后的实例中,我希望连接器输入出现,提供“AND”或“OR”选项。当我创建它时,我收到错误:ERROR: Cannot find control with path: 'statement → groups → 1 → conjunctor来自 AppComponent。

AppComponent 的外观如下:

<form [formGroup]="_form">
    <ng-container formGroupName="statement">
        <ng-container formArrayName="groups">
            <ng-container *ngFor="let group of _groupsFormArray?.controls; index as i">
         <div *ngIf="i > 0">
           <div [formGroupName]="i">
             <input type="text" formControlName="conjunctor">
           </div>
         </div>
            <app-group-control 
             (remove)="_delete(i)"
             [formControlName]="i"
             [formLabel]="'Group '+ (i + 1) + ':'">
            </app-group-control>
            </ng-container>
        </ng-container>
    </ng-container>
</form>

如您所见,有一个div包含 ngIf 逻辑:

<div *ngIf="i > 0">
  <div [formGroupName]="i">
    <input type="text" formControlName="conjunctor">
  </div>
</div>

这种方法不起作用,但我尝试过的其他方法也没有。

到目前为止,我多次尝试将 FormGroupName 更改为groups, statements, i, index,但没有任何改善。

我还尝试使用模板 ref跟踪ngForAppComponent中的每个实例,@ViewChildren('templateRef') templateRefVar: QueryList<ElementRef>;然后在ref 中跟踪每个实例。从那里,我使用 ngIf 将其传递给我的子组件,然后使用内部的 ngIf 。这是我得到的最接近的,但问题是,每次满足 ngIf 条件时,它都会出现在组数组的每个实例上,包括第一个实例,并给我错误:。这是我使用此方法获得的最接近的 StackBlitz。这是上面代码中的 StackBlitzngFor#templateReftemplateRef.lengthGroupControlComponent@Input() groupInstancesExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '0'. Current value: '1'.

如果您想了解有关此递归形式的更多信息,可以在此处阅读。

标签: angularangular-forms

解决方案


Stackblitz 演示

让我们替换groupInstanceforshowConjunctor只是为了更清楚地了解它的用途。

你可以这样做app.component.hml

<app-group-control 
  #templateRef
  (remove)="_delete(i)"
  [formControlName]="i"
  [formLabel]="'Group '+ (i + 1) + ':'"
  [showConjunctor]="!((i + 1) % 2)">
</app-group-control>

我正在考虑i,在上面的片段中,是当前循环的索引*ngFor(就像在 Stackblitz 演示中一样)。

此外,从 中删除此部分app.component.html

<div *ngIf="i > 0">
  <div [formGroupName]="i">
    <input type="text" formControlName="conjunctor">
  </div>
</div>

[更新]:根据您的评论,如果您想在所有嵌套组中使用连接器,您可以在(Stackblitz 演示@Input() showConjuntor)中将其设置为 true :GroupControlComponent

<ng-container formArrayName="groups">
  <app-group-control *ngFor="let s of _groupsFormArray?.controls; index as i"
                      (remove)="_deleteGroupFromArray(i)" 
                      [formControlName]="i"
                      [formLabel]="'Nested Group '+ (i + 1) + ':'"
                      [showConjunctor]="true">
  </app-group-control>
</ng-container>

推荐阅读