Угловой материал, плоское дерево, графическое представление родителей и детей
Я хочу показать графическое представление родительских детей на плоском дереве углового материала.
Это дизайн:
ht tps:https://stackru.com/images/c289d68a73885b848e57ec622d68e6a11bfaca25.jpg
Вот ДЕМО, что я сделал до сих пор.
1 ответ
ПЕРВОЕ РЕШЕНИЕ
вот стек Blitz Demo
вот редактируемая ссылка 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
другое решение - отслеживать последний элемент в массиве, добавляя, например, 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>