Угловой Материал Плоское Дерево Родитель Дети Графическое Представление - PullRequest
6 голосов
/ 01 октября 2019

Я хочу показать графическое представление Parent Children на Angular Material Flat Tree.

Это дизайн:

enter image description here

Вот DEMO что я сделал до сих пор.

1 Ответ

3 голосов
/ 05 октября 2019

ПЕРВОЕ РЕШЕНИЕ

вот демо stackBlitz

вот редактируемая ссылка stackBlitz

Я сделал рекурсивный вызов на каждом видимом узле, ссылающемся на индекс узла, используя treeControl.dataNodes.indexOf(node)

, вот рекурсивная функция:

  recNode(arr:any[], data:any[], index:number, maxIndex:number):any[]{
    if (arr === undefined)
      arr = [];
    for (let i = 0; i < data.length; i++){
          index++
          if (index === maxIndex)
            return ([true, index, arr]);
          if (data[i].children.length){
            let res = this.recNode(arr, data[i].children, index, maxIndex)
            index = res[1];
            if (res[0] === true)
            {
              arr.splice(0, 0, (i !== (data.length - 1)))         
              return ([true, index, arr]);
            }
        }
    }
    return ([false, index, arr]);
  }

, которая возвращает массив true false значения для вашего [ngClass]

, затем в html я вызываю эту функцию следующим образом:

<li *ngFor="let r of recNode(undefined, dataSource.data, -1, treeControl.dataNodes.indexOf(node))[2]; [ngClass]="{'node-arrow': r, 'node-arrow-empty': !r}" ></li>

и, наконец, я создал еще один класс в css под названием node-arrow-empty безГраницы

   .node-arrow-nox {
      position: relative;
      // min-width: 48px;
      // min-height: 48px;
      .node-arrow {
        position: relative;
        min-width: 48px;
        min-height: 48px;
        &:before {
          content: "";
          position: absolute;
          top: -20px;
          left: 20px;
          border-left: 1px solid $copounsCount;
          bottom: 0;
        }
      }
      .node-arrow-empty {
        position: relative;
        min-width: 48px;
        min-height: 48px;
        &:before {
          content: "";
          position: absolute;
          top: -20px;
          left: 20px;
          bottom: 0;
        }
      }
    }

в зависимости от того, какой из значений в массиве равен true или false, он переключает html между двумя классами.

ВТОРОЕ РЕШЕНИЕ

stackBlitz DEMO

редактируемая ссылка stackBlitz

другое решение будет отслеживать последний элемент в массиве путем добавлениянапример свойство isLast:boolean. Конечно, если данные, с которыми вы имеете дело, являются динамическими, вам нужно найти способ динамически изменить это значение.

После заполнения isLast вы делаете рекурсивный вызов, который обнаружит предыдущего брата с current node level - 1. При этом вы проверите 2 вещи. Во-первых, классы узлов содержат n-last (это имя класса, которое я дал Html, представляющему последний элемент родительского массива), а во-вторых, рекурсивно извлекаем класс n-{{node-level}}.

. сделайте нерекурсивный метод, если вы не хотите), извлекая previousElementSibling с классом n-3 или n-2 ... в n-0, вы можете проверить, содержит ли каждый из этих элементов класс n-last. Вы помещаете true или false в массив, и как первое решение переключается между классами node-arrow и node-arrow-empty.

, здесь есть рекурсивная функция

  dummy(el:any, arr:any[], level:number){
    let classes = el.className;
    if (arr === undefined)
     arr = [];
    else{
     arr.splice(0, 0, classes.includes('n-last'));
    }
    let np = /(?!n-)\d+/g;
    let m = classes.match(np);
    let nLevel = parseInt(m[0]);
    nLevel--
    if (nLevel < 0)
      return (arr)
    while (parseInt(el.className.match(np)[0]) !== nLevel){
      el = el.previousElementSibling
    }
    arr = this.dummy(el, arr, nLevel)
    return (arr)
  }

HTML (здесь только родительский узел, но то же самое для дочернего)

<mat-tree-node #refP   class="parent-node {{'n-' + node.level}} " *matTreeNodeDef="let node; when: grpNode;" matTreeNodePadding matTreeNodePaddingIndent="0" cdkDrag [cdkDragData]="node" [ngClass]="{'no-child': !node.children.length, 'n-last': node.isLast}">
  <span class="node-arrow-nox d-flex">
    <li [ngClass]="{'node-arrow': !r , 'node-arrow-empty': r}" *ngFor="let r of dummy(refP, undefined, node.level)"></li>
  </span>
  <button class="node-toggle" mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.filename" [disabled]="!node.children.length">
    <mat-icon class="mat-icon-rtl-mirror toggle-arrow">
      {{treeControl.isExpanded(node) ? 'play_arrow' : 'play_arrow'}}
    </mat-icon>
  </button>
  <div class="node-icon icon-h-arw"></div>
  <div class="node-name">{{node.isLast}}-{{node.accntCode}} <span>: :</span> {{node.name}} </div>
</mat-tree-node>

, как вы можете видеть, я передаю элемент фиктивной функции с помощью переменной шаблона #refP

и вот декларации PARENTNODE и CHILDNODE:

export class PARENTNODE {
  id: string;
  isLast: boolean;
  ...
  actAsSupplier: boolean;
}

/* Flat node with expandable and level information */
export class CHILDNODE {
  constructor(
    public id: string,
    public isLast: boolean,
    ...
    public actAsSupplier: boolean,
  ){}
}

ТРЕТЬЕ РЕШЕНИЕ

Я не буду кодировать это, но я попытаюсь объяснить это.

Это похоже на предыдущее решение, за исключением того, что вы можете выполнить синтаксический анализ при изменении дерева (замена, удаление, добавление) данных и добавить свойство, например divType, заполненное true или falseи назовите это в своем HTML как

 <li *ngFor="let r of node.divType" [ngClass]="{'node-arrow': r, 'node-arrow-empty': !r}" ></li>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...