使用 json 对象列表以角度生成层次结构视图

Posted

技术标签:

【中文标题】使用 json 对象列表以角度生成层次结构视图【英文标题】:Generating a hierarchy view in angular with a list of json objects 【发布时间】:2019-10-14 07:26:34 【问题描述】:

我目前正在尝试构建用户的层次结构视图。我的最终目标是使用this hierarchy view 生成视图 或类似的东西。

难点在于如何给出用于生成层次结构的 JSON 对象。这是一个示例响应(此响应可能更大),其中 pid 是父 id,depth 是与第一个父的距离。

response = [
    uid: "abc", pid: null, depth: 1, parent: true,
    uid: "def", pid: "abc", depth: 2, parent: false,
    uid: "ghi", pid: "abc", depth: 2, parent: true,
    uid: "jkl", pid: "ghi", depth: 3, parent: false,
    uid: "mno", pid: "ghi", depth: 3, parent: false,
]

为了更好地解释上面的响应,这里是它的视觉层次视图: image

到目前为止,我看到的许多答案和解决方案都使用 JSON,每个子节点都嵌套在其中。是否可以使用上面的 json 模型生成视图?

任何帮助或见解将不胜感激!谢谢!

【问题讨论】:

好吧。我是否正确,您需要从数据中获取图表(图表)? 是的,我需要一张图表。就像那个一样,我在第一段中链接了。 【参考方案1】:

首先,您需要将自引用表转换为分层表(树)。我建议您使用custom pipe 来执行此操作,因为您将能够在其他地方重复使用此管道。

您可以使用 Reactgular 的代码、我来自 *** 线程的代码,或者编写您自己的代码。我用 Reactgular 的代码创建了我的 converter 管道:

converter.pipe.ts

import  Pipe, PipeTransform  from '@angular/core';

@Pipe(
  name: 'converter'
)
export class ConverterPipe implements PipeTransform 
  transform(array: any[], id: string = 'uid', parentId: string = 'pid'): any[] 
    const map = array.reduce(
      (acc, node) => ((node.items = []), (acc[node[id]] = node), acc),
      
    );

    return Object.values(map)
      .map(
        node => (node[parentId] && map[node[parentId]].items.push(node), node)
      )
      .filter(node => node[parentId] === null);
  

不要忘记将其添加到模块的 declaration 部分:

app.module.ts

import  ConverterPipe  from './converter.pipe';

@NgModule(
  declarations: [
    ConverterPipe
  ]
)
export class AppModule  

现在,您可以创建组件模板并使用Hierarchy View CodePen 中的方法。由于您需要为树枝和树叶使用不同的标记,因此使用NgTemplateOutlet's 和NgIf structural directives 很方便。当您需要在 Angular 中渲染树时,在模板中移动关卡标记并重用它是一个好主意。我的answer 说明了相同的想法。根据提供的 CodePen 代码,您的 Angular 标记可能如下所示:

app.component.html

<div class="hv-wrapper">
  <ng-template #Item let-item>
    <ng-container *ngIf="!item.items.length; else Component">
      <p> item.uid </p>
    </ng-container>
    <ng-template #Component>
      <div class="hv-item">
        <div class="hv-item-parent">
          <p> item.uid </p>
        </div>
        <div class="hv-item-children">
          <div class="hv-item-child" *ngFor="let child of item.items">
            <ng-container
              *ngTemplateOutlet="Item; context:  $implicit: child "
            ></ng-container>
          </div>
        </div>
      </div>
    </ng-template>
  </ng-template>

  <ng-container *ngFor="let child of response | converter"
    ><ng-container
      *ngTemplateOutlet="Item; context:  $implicit: child "
    ></ng-container
  ></ng-container>
</div>

这里,response 是您的原始数组:

app.component.ts

export class AppComponent 
  response = [
     uid: 'abc', pid: null, depth: 1, parent: true ,
     uid: 'def', pid: 'abc', depth: 2, parent: true ,
     uid: 'ghi', pid: 'abc', depth: 2, parent: false ,
     uid: 'jkl', pid: 'ghi', depth: 3, parent: false ,
     uid: 'mno', pid: 'ghi', depth: 3, parent: false 
  ];

不要忘记在您的项目中使用 CodePen SASS 样式。

在此之后,您将得到如下图:

这是一个StackBlitz project,展示了这种方法的实际应用。

【讨论】:

【参考方案2】:

您可以使用 reducer 将平面数组转换为节点的 UID 映射,一旦您拥有映射,您就可以轻松地填充子节点。然后,您可以选择根节点并使用它来呈现 html

const map = [
   uid: "abc", pid: null, depth: 1, parent: true,
   uid: "def", pid: "abc", depth: 2, parent: true,
   uid: "ghi", pid: "abc", depth: 2, parent: false,
   uid: "jkl", pid: "ghi", depth: 3, parent: false,
   uid: "mno", pid: "ghi", depth: 3, parent: false,
].reduce((acc, node) => (node.children = [], acc[node.uid] = node, acc), );

const [root] =  Object.values(map)
                      .map(node => (node.pid && map[node.pid].children.push(node), node))
                      .filter(node => node.pid === null);
    
console.log(root);

您可以使用相同的组件递归地渲染树,并让模板渲染孩子。

@Component(
      selector: 'app-node',
      template: `
          <span>Node</span>
          <app-node [node]="child" *ngFor="let child of node.children"></app-node>
      `
)
export class NodeComponent 
    @Input()
    public node: any;

修改上述内容以匹配您在问题中链接到的 HTML/CSS 并不难。

【讨论】:

以上是关于使用 json 对象列表以角度生成层次结构视图的主要内容,如果未能解决你的问题,请参考以下文章

如何遍历从 REST API 获得的响应对象并以角度 2 在视图中显示数据

以角度 6 处理 json 对象

以角度 5 在 HTML 上显示来自 json 对象的数据

如何以角度4打印角度对象

如何以角度将数组推送到 JSON 对象

如何以角度将 JSON 对象数组转换为 Observable 数组