如何在 Angular Material 嵌套树中获取节点兄弟姐妹?
How to get node siblings in an Angular Material nested tree?
我正在尝试获取嵌套树中给定 Angular Material 树节点的兄弟节点列表。
我正在研究 Angular Material 官方 docs,特别是 "Tree with nested nodes"。 NestedTreeControl
和我无法通过 @angular/cdk/collections
访问的 SelectionModel
都没有提供访问甚至查看给定节点的兄弟节点的方法。他们甚至不提供一种方法来了解您所在的 NESTED 树的级别,除非您使用的是平面树。
这是HTML
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="example-tree">
<!-- This is the tree node template for leaf nodes -->
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
<li class="mat-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<button mat-icon-button disabled></button>
{{node.name}}
</li>
</mat-tree-node>
<!-- This is the tree node template for expandable nodes -->
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<li>
<div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'toggle ' + node.name">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.name}}
</div>
<ul [class.example-tree-invisible]="!treeControl.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
这是class代码
import {NestedTreeControl} from '@angular/cdk/tree';
import {Component} from '@angular/core';
import {MatTreeNestedDataSource} from '@angular/material/tree';
/**
* Food data with nested structure.
* Each node has a name and an optiona list of children.
*/
interface FoodNode {
name: string;
children?: FoodNode[];
}
const TREE_DATA: FoodNode[] = [
{
name: 'Fruit',
children: [
{name: 'Apple'},
{name: 'Banana'},
{name: 'Fruit loops'},
]
}, {
name: 'Vegetables',
children: [
{
name: 'Green',
children: [
{name: 'Broccoli'},
{name: 'Brussel sprouts'},
]
}, {
name: 'Orange',
children: [
{name: 'Pumpkins'},
{name: 'Carrots'},
]
},
]
},
];
/**
* @title Tree with nested nodes
*/
@Component({
selector: 'tree-nested-overview-example',
templateUrl: 'tree-nested-overview-example.html',
styleUrls: ['tree-nested-overview-example.css'],
})
export class TreeNestedOverviewExample {
treeControl = new NestedTreeControl<FoodNode>(node => node.children);
dataSource = new MatTreeNestedDataSource<FoodNode>();
constructor() {
this.dataSource.data = TREE_DATA;
}
hasChild = (_: number, node: FoodNode) => !!node.children && node.children.length > 0;
}
还有一些CSS
.example-tree-invisible {
display: none;
}
.example-tree ul,
.example-tree li {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
我只需要一种访问兄弟节点的方法。当我使用 NESTED 树时,我也真的需要根据我所在的节点知道我在哪个级别。
对于任何寻求此答案的人,我按如下方式解决了我的问题。
- 首先为节点class 创建自定义数据属性。
这是我现在的节点 class:
import {NestedTreeControl} from '@angular/cdk/tree';
import {Component} from '@angular/core';
import {MatTreeNestedDataSource} from '@angular/material/tree';
/**
* Food data with nested structure.
* Each node has a name and an optional list of children.
*/
interface FoodNode {
name: string;
children?: FoodNode[];
}
export class FoodNode {
children: BehaviorSubject<FoodNode[]>;
constructor(
public name: string,
public type: string,
public id: number,
children?: FoodNode[],
public parent?: FoodNode,
public level = 0
) {
this.children = new BehaviorSubject(children === undefined ? [] : children);
}
}
- 第二个嵌套树class如下
import { NestedTreeControl } from '@angular/cdk/tree';
export class NestedTreeComponent implements OnInit, OnDestroy {
// TREE CONTROLS
treeControl: NestedTreeControl<FoodNode>;
foodTreeLevels = [];
treeDepth = 1; // initialize tree with default depth 1
ngOnInit() {
// initialize tree controls and data source
this.treeControl = new NestedTreeControl<FoodNode>(this.getChildren);
}
/** Get node children */
getChildren = (node: FoodNode): Observable<FoodNode[]> => node.children;
/**
* @desc Add the node to its parent's children object
*/
addNewFood(parent: FoodNode, foodName: string, foodType: string, foodId: number) {
// Add the food to the list of children
const child = new FoodNode(foodName, foodType, foodId, [], parent, 0);
child.level = parent.level + 1;
// add a new level to the tree if the parent of this node has no children yet
if (parent && parent.children.value.length === 0 && !this.foodTreeLevels.includes(child.level)) {
this.foodTreeLevels.push(child.level);
this.treeDepth += 1;
}
// update the parents' children with this newly added node if the parent exists
if (parent) {
const children = parent.children.value;
children.push(child);
parent.children.next(children);
}
}
- 现在,无论您需要访问树中任何节点的兄弟节点,只需转到父节点,然后获取其所有子节点,如下所示:
// This is a node of type FoodNode
const parent = theNodeINeedToGetSiblingsFor.parent;
const siblings = parent.children.value;
我正在尝试获取嵌套树中给定 Angular Material 树节点的兄弟节点列表。
我正在研究 Angular Material 官方 docs,特别是 "Tree with nested nodes"。 NestedTreeControl
和我无法通过 @angular/cdk/collections
访问的 SelectionModel
都没有提供访问甚至查看给定节点的兄弟节点的方法。他们甚至不提供一种方法来了解您所在的 NESTED 树的级别,除非您使用的是平面树。
这是HTML
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="example-tree">
<!-- This is the tree node template for leaf nodes -->
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
<li class="mat-tree-node">
<!-- use a disabled button to provide padding for tree leaf -->
<button mat-icon-button disabled></button>
{{node.name}}
</li>
</mat-tree-node>
<!-- This is the tree node template for expandable nodes -->
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<li>
<div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'toggle ' + node.name">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.name}}
</div>
<ul [class.example-tree-invisible]="!treeControl.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
这是class代码
import {NestedTreeControl} from '@angular/cdk/tree';
import {Component} from '@angular/core';
import {MatTreeNestedDataSource} from '@angular/material/tree';
/**
* Food data with nested structure.
* Each node has a name and an optiona list of children.
*/
interface FoodNode {
name: string;
children?: FoodNode[];
}
const TREE_DATA: FoodNode[] = [
{
name: 'Fruit',
children: [
{name: 'Apple'},
{name: 'Banana'},
{name: 'Fruit loops'},
]
}, {
name: 'Vegetables',
children: [
{
name: 'Green',
children: [
{name: 'Broccoli'},
{name: 'Brussel sprouts'},
]
}, {
name: 'Orange',
children: [
{name: 'Pumpkins'},
{name: 'Carrots'},
]
},
]
},
];
/**
* @title Tree with nested nodes
*/
@Component({
selector: 'tree-nested-overview-example',
templateUrl: 'tree-nested-overview-example.html',
styleUrls: ['tree-nested-overview-example.css'],
})
export class TreeNestedOverviewExample {
treeControl = new NestedTreeControl<FoodNode>(node => node.children);
dataSource = new MatTreeNestedDataSource<FoodNode>();
constructor() {
this.dataSource.data = TREE_DATA;
}
hasChild = (_: number, node: FoodNode) => !!node.children && node.children.length > 0;
}
还有一些CSS
.example-tree-invisible {
display: none;
}
.example-tree ul,
.example-tree li {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
我只需要一种访问兄弟节点的方法。当我使用 NESTED 树时,我也真的需要根据我所在的节点知道我在哪个级别。
对于任何寻求此答案的人,我按如下方式解决了我的问题。
- 首先为节点class 创建自定义数据属性。 这是我现在的节点 class:
import {NestedTreeControl} from '@angular/cdk/tree';
import {Component} from '@angular/core';
import {MatTreeNestedDataSource} from '@angular/material/tree';
/**
* Food data with nested structure.
* Each node has a name and an optional list of children.
*/
interface FoodNode {
name: string;
children?: FoodNode[];
}
export class FoodNode {
children: BehaviorSubject<FoodNode[]>;
constructor(
public name: string,
public type: string,
public id: number,
children?: FoodNode[],
public parent?: FoodNode,
public level = 0
) {
this.children = new BehaviorSubject(children === undefined ? [] : children);
}
}
- 第二个嵌套树class如下
import { NestedTreeControl } from '@angular/cdk/tree';
export class NestedTreeComponent implements OnInit, OnDestroy {
// TREE CONTROLS
treeControl: NestedTreeControl<FoodNode>;
foodTreeLevels = [];
treeDepth = 1; // initialize tree with default depth 1
ngOnInit() {
// initialize tree controls and data source
this.treeControl = new NestedTreeControl<FoodNode>(this.getChildren);
}
/** Get node children */
getChildren = (node: FoodNode): Observable<FoodNode[]> => node.children;
/**
* @desc Add the node to its parent's children object
*/
addNewFood(parent: FoodNode, foodName: string, foodType: string, foodId: number) {
// Add the food to the list of children
const child = new FoodNode(foodName, foodType, foodId, [], parent, 0);
child.level = parent.level + 1;
// add a new level to the tree if the parent of this node has no children yet
if (parent && parent.children.value.length === 0 && !this.foodTreeLevels.includes(child.level)) {
this.foodTreeLevels.push(child.level);
this.treeDepth += 1;
}
// update the parents' children with this newly added node if the parent exists
if (parent) {
const children = parent.children.value;
children.push(child);
parent.children.next(children);
}
}
- 现在,无论您需要访问树中任何节点的兄弟节点,只需转到父节点,然后获取其所有子节点,如下所示:
// This is a node of type FoodNode
const parent = theNodeINeedToGetSiblingsFor.parent;
const siblings = parent.children.value;