在支持带有动态数据的嵌套mat-tree的实现中,我可以看到在展开树项时正在加载数据,但是子项从未得到渲染。
我从Angular Material的文档中获取了示例代码,并尝试根据自己的需要进行调整。不幸的是,我不能说我完全理解那里发生的事情,因此我一直无法解决问题。
主要成分:
export class TrackableBrowserComponent {
nestedTreeControl: NestedTreeControl<CategoryNode>;
nestedDataSource: CategoryDataSource;
hasNestedChild = (_: number, node: CategoryNode) => true;
getChildren = (node: CategoryNode) => node.children;
constructor(categoryService: CategoryService) {
this.nestedTreeControl = new NestedTreeControl<CategoryNode>(this.getChildren);
this.nestedDataSource = new CategoryDataSource(categoryService, this.nestedTreeControl);
}
}
mat树的渲染方式如下:
<mat-tree [dataSource]="nestedDataSource" [treeControl]="nestedTreeControl" class="example-tree">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
<li class="mat-tree-node">
<button mat-icon-button disabled></button>
{{node.name}}: {{node.type}}
</li>
</mat-tree-node>
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild">
<li>
<div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle>
<mat-icon class="mat-icon-rtl-mirror">{{nestedTreeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}</mat-icon>
</button>
{{node.name}}
</div>
<ul [class.example-tree-invisible]="!nestedTreeControl.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
这是可能包含问题的部分。
export class CategoryNode {
name: string;
description: string;
children: CategoryNode[] = [];
category: Category;
static from(category: Category): CategoryNode {
const n = new CategoryNode();
n.name = category.name;
n.category = category;
n.children = [];
return n;
}
}
export class CategoryDataSource implements DataSource<CategoryNode> {
dataChange: BehaviorSubject<CategoryNode[]> = new BehaviorSubject<CategoryNode[]>([]);
constructor(
private categoryService: CategoryService,
private treeControl: NestedTreeControl<CategoryNode>
) {
this.categoryService.getAll().pipe(
map(categories => categories.map(c => CategoryNode.from(c)))
).subscribe(nodes => this.data = nodes);
}
connect(collectionViewer: CollectionViewer): Observable<CategoryNode[]> {
console.log('collect(): called');
this.treeControl.expansionModel.changed.subscribe(change => {
console.log('collect(): received change event from treeControl.expansionModel');
if ((change as SelectionChange<CategoryNode>).added ||
(change as SelectionChange<CategoryNode>).removed) {
this.handleTreeControl(change as SelectionChange<CategoryNode>);
}
});
return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data));
}
disconnect(collectionViewer: CollectionViewer): void {
throw new Error('Method not implemented.');
}
get data(): CategoryNode[] {
return this.dataChange.value;
}
set data(value: CategoryNode[]) {
this.treeControl.dataNodes = value;
this.dataChange.next(value);
}
handleTreeControl(change: SelectionChange<CategoryNode>) {
if (change.added) {
console.log('handleTreeControl(): added');
change.added.forEach(node => this.toggleNode(node, true));
} else if (change.removed) {
console.log('handleTreeControl(): removed');
change.removed.slice().reverse().forEach(node => this.toggleNode(node, false));
} else {
console.log('handleTreeControl(): other');
}
}
toggleNode(node: CategoryNode, expand: boolean) {
console.log('toggleNode(): called');
if (expand === true) {
console.log('toggleNode(): expanding node ' + node.name);
node.category.children.pipe(map(all => all.map(item => CategoryNode.from(item)))).subscribe(nodes => {
console.log('toggleNode(): received data ' + JSON.stringify(nodes));
node.children = nodes;
this.treeControl.dataNodes = this.data;
this.dataChange.next(this.data);
});
}
}
}
我需要补充一点,我的Category
实体具有一个名为“ children”的ReplaySubject,该实体将向后端API触发GET / cartegories / ID / children调用。
export class Category extends BaseEntity<CategoryLinks> {
name: string;
description: string;
parent: ReplaySubject<Category>;
children: ReplaySubject<Category[]>;
}
我的总体想法是在展开项目时将Category
中的CategoryNode
变形并将ReplaySubject的结果复制到CategoryNode
的“ children”属性中。这部分似乎有效,因为我可以看到
console.log('toggleNode(): received data ' + JSON.stringify(nodes));
在浏览器日志中。
我认为现在连接到该DataSource的任何人都应得到有关该更改的通知,并相应地进行更新。但这不会发生。我按了树上的扩展按钮,触发了后端调用,但是UI中什么也没发生。
有什么想法吗?