Создание представления иерархии в angular со списком объектов json

В настоящее время я пытаюсь построить иерархическое представление пользователей. Моя конечная цель - создать представление, используя это представление иерархии или что-то подобное.

Сложность заключается в том, как задаются объекты JSON, используемые для создания иерархии. Это пример ответа (этот ответ может быть намного больше), где pid — это идентификатор родителя, а глубина — это расстояние от первого родителя.

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},
]

Чтобы лучше объяснить приведенный выше ответ, вот его визуальная иерархия: изображение

Создание представления иерархии в angular со списком объектов json

Многие ответы и решения, которые я видел до сих пор, используют JSON с дочерними элементами, вложенными в каждый из них. Можно ли сгенерировать представление, используя приведенную выше модель json?

Любая помощь или понимание будут высоко оценены! Спасибо!

Хорошо. Я правильно понимаю, что вам нужно получить диаграмму (график) из ваших данных?

Gosha_Fighten 28.05.2019 20:05

Да, мне нужно получить схему. Как тот, который я связал в первом абзаце.

Aido 28.05.2019 20:16
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
3
2
3 337
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете использовать редуктор для преобразования плоского массива в карту узлов 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.info(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, на который вы ссылались в своем вопросе.

Ответ принят как подходящий

Во-первых, вам нужно преобразовать вашу таблицу ссылок на себя в иерархическую таблицу (дерево). Я предлагаю вам использовать нестандартная труба для этого, так как вы сможете повторно использовать этот канал в других местах.

Вы можете использовать код Reactgular, мой код из темы Переполнение стека или написать свой собственный код. Я создаю свой канал converter с кодом Reactgular:

конвертер.труба.ц

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

Теперь вы можете создать свой шаблон компонента и использовать подход из Представление иерархии CodePen. Поскольку вам нужна разная разметка для ветвей и листьев, удобно использовать NgTemplateOutlet и NgIf структурные директивы. Это хорошая идея — переместить разметку уровня в шаблон и повторно использовать ее, когда вам нужно отобразить дерево в Angular. Та же идея проиллюстрирована в моем отвечать. На основе предоставленного кода 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 в своем проекте.

После этого вы получите график вида:

graph

Это Проект StackBlitz, демонстрирующий этот подход в действии.

Другие вопросы по теме