【问题标题】:Angular Recursive Component with *ngFor and async pipe goes in loop带有 *ngFor 和异步管道的角递归组件进入循环
【发布时间】:2018-10-05 13:31:03
【问题描述】:

我试图以 Angular 创建动态内容树。如下所示。

vehicles
  - cars
     - vw
       - golf
       - passat
     - ford
       - fiesta
     - toyota
  - Buses
    - volvo
    - Scania
Animals
  - carnivorous
    - Lion
    - tiger
  - Herbivorous
    - Cow
    - Horse

我有一个内容树组件和一个树节点组件。我试图根据章节的数量动态地在树中创建孩子。由于 DocRootNode 是一个 observable,我必须在代码中使用异步管道。我递归地使用树节点来创建动态树。

内容树.html:

<tree-node *ngFor="let docChildNode of DocRootNode$ | async"
                 [node]="docChildNode">
</tree-node>

树节点.html:

  <div class="children" *ngIf="node.children">
    <tree-node *ngFor="let childDocNode of node.children" [node]="childDocNode" >
    </tree-node>
  </div>

一切都按预期工作。但是我发现了一个问题,即在后台递归正在循环中。例如:我添加了 [ngClass] = "{ isActive: isActive(node) }" 并在 isActive 函数中,我做了一个控制台日志,我发现日志正在循环中。我找不到原因。我是 Angular 的新手。非常感谢任何帮助。

更新日志。数字是节点

tree-node.component.ts:78 This one 4
tree-node.component.ts:78 This one 6
tree-node.component.ts:78 This one 3
tree-node.component.ts:78 This one 3-0
tree-node.component.ts:78 This one 3-0-0
tree-node.component.ts:78 This one 3-0-0-0
tree-node.component.ts:78 This one 3-0-0-2
tree-node.component.ts:78 This one 3-0-1
tree-node.component.ts:78 This one 3-0-2
tree-node.component.ts:78 This one 3-0-2-0
tree-node.component.ts:78 This one 3-0-2-1
tree-node.component.ts:78 This one 3-0-2-2
tree-node.component.ts:78 This one 3-1-0-0
tree-node.component.ts:78 This one 3-1-1
tree-node.component.ts:78 This one 3-1-1-0

tree-node.component.ts:78 This one 4
tree-node.component.ts:78 This one 6
tree-node.component.ts:78 This one 3
tree-node.component.ts:78 This one 3-0
tree-node.component.ts:78 This one 3-0-0
tree-node.component.ts:78 This one 3-0-0-0
tree-node.component.ts:78 This one 3-0-0-2
tree-node.component.ts:78 This one 3-0-1
tree-node.component.ts:78 This one 3-0-2
tree-node.component.ts:78 This one 3-0-2-0
tree-node.component.ts:78 This one 3-0-2-1
tree-node.component.ts:78 This one 3-0-2-2
tree-node.component.ts:78 This one 3-1-0-0
tree-node.component.ts:78 This one 3-1-1
tree-node.component.ts:78 This one 3-1-1-0

tree-node.component.ts:78 This one 4
tree-node.component.ts:78 This one 6
tree-node.component.ts:78 This one 3
tree-node.component.ts:78 This one 3-0
tree-node.component.ts:78 This one 3-0-0
tree-node.component.ts:78 This one 3-0-0-0
tree-node.component.ts:78 This one 3-0-0-1
tree-node.component.ts:78 This one 3-0-0-2
tree-node.component.ts:78 This one 3-0-1
tree-node.component.ts:78 This one 3-0-2
tree-node.component.ts:78 This one 3-0-2-0
tree-node.component.ts:78 This one 3-0-2-1
tree-node.component.ts:78 This one 3-0-2-2
tree-node.component.ts:78 This one 3-1-1
tree-node.component.ts:78 This one 3-1-1-0

补充

【问题讨论】:

  • “进入循环”是什么意思?请分享控制台日志输出并解释其中的问题。
  • 日志重复,页面挂起
  • 如果可能,请考虑创建StackBlitz
  • 更新了日志。
  • 可能是 Angular 无法正确检测对象更改的问题。您是否尝试将 trackBy 表达式添加到您的 ngFors 中?

标签: angular recursion tree observable ngfor


【解决方案1】:

让我们看看从父节点开始渲染节点。

export interface TreeNode<T> {
    value: T;
    children: Array<TreeNode<T>>;
    parent?: TreeNode<T>;
}

根据您的输入,您将渲染这棵树。

vehicles
  - cars
     - vw
       - golf
       - passat

{
    value: 'vehicles',
    children: [
        {
            value: 'cars',
            children: [
                {
                    value: 'vw',
                    children: [
                        {
                            value: 'golf',
                            children: [],
                            parent: /* linked to 'vw' node */
                        },
                        {
                            value: 'passat',
                            children: [],
                            parent: /* linked to 'vw' node */
                        }
                    ],
                    parent: /* linked to 'cars' node */
                }
            ]
        }
    ],
    parent: undefined /*or null*/
}

您需要使用广度优先算法分配父节点。

下面的模板现在可以渲染您创建的树。 它将获取最顶层的节点并显示名称。

使用和 *ngTemplateOutlet,我们可以通过设置上下文的 $implicit 值将子节点列表发送到要渲染的。 在 ng-template 中,我们将有一些逻辑来呈现名称并递归调用相同的 ng-template(如果它有子级)。这将创建您的树。

您必须添加适合您的应用程序的正确样式。

<div *ngIf="tree?.value">
    <h2> {{tree.value.name}}</h2>
</div>
<div *ngIf="tree?.children">
    <ng-template #recursiveList let-list>
        <div *ngFor="let node of list">
            <h5>{{node.value.name}}</h5>
            <div *ngIf="node.children.length > 0">
                <ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: node.children }"></ng-container>
            </div>
        </div>
    </ng-template>
    <ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: tree.children }"></ng-container>
</div>

文档: https://angular.io/api/common/ngTemplateOutlet https://angular.io/guide/structural-directives

【讨论】:

  • 你能解释一下吗?
  • 此逻辑将从顶部父节点一次创建一棵树。因此,您将需要一个更高级别的组件来呈现树列表并且它会起作用。
猜你喜欢
  • 1970-01-01
  • 2018-02-03
  • 2018-01-09
  • 2018-04-18
  • 2019-04-11
  • 2017-11-04
  • 2020-01-15
  • 1970-01-01
  • 2015-06-09
相关资源
最近更新 更多