当我将新数据设置为this.dataSource.data
时,我需要保持树节点处于打开/关闭状态。新数据与旧数据非常相似-仅添加或删除了一个或几个最低级别的节点。
我的想法是将节点扩展记录到ReplaySubject
并重播扩展队列。它应该工作,但是这是非常丑陋的方式。
我希望这里有解决我问题的更优雅的方法。
答案 0 :(得分:1)
我具有要显示在材料树中的数据对象的层次结构。每个数据对象都转换为一个TreeNodeModel,其中包含原始数据对象的ID和ParentID。 在更新数据源的方法中,保存/恢复节点的扩展状态:
// Method that updates the data source
public updateDataSource(dataObjects: SomeDataObject) {
// save node's expanded state
const expandedNodesIds: string[] = [];
if (this.treeControl.dataNodes) {
this.treeControl.dataNodes.forEach((node: TreeNodeModel) => {
if (this.treeControl.isExpandable(node) && this.treeControl.isExpanded(node)) {
expandedNodesIds.push(node.id);
}
});
}
// update data source
this.treeDataSource.data = dataObjects;
// restore node's expanded state
this.treeControl.dataNodes
.filter(node => this.isActive(node) || expandedNodesIds.find(id => id === node.id))
.forEach(nodeToExpand => {
this.expandNode(nodeToExpand);
});
}
// Method that expands the node (if not a leave) and its parent nodes (if any) using the TreeControl
private expandNode(treeNode: TreeNodeModel | undefined): void {
if (!treeNode) {
return;
}
if (this.treeControl.isExpandable(treeNode)) {
this.treeControl.expand(treeNode);
}
const parentId = treeNode.parentId ? treeNode.parentId : undefined;
this.expandNode(this.treeControl.dataNodes.find(node => node.id === parentId));
}
答案 1 :(得分:0)
我在数据模型中添加了一个布尔值“扩展”。然后,我在(click)上使用一个将其反转的函数,并使用递归循环将所做的更改保存到用于dataSource.data的实际数据中。因此,实际上我不再使用treecontrol,即使我仍然需要它(树不能没有它)。
<button mat-icon-button
[attr.aria-label]="'toggle ' + node.name"
(click)="changeState(node, myJson)"
>
<mat-icon class="mat-icon-rtl-mirror">
{{node.expanded ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
-
/** Changes expanded state for clicked tree-item, saves change to json data used by tree datasource */
changeState(node, myJson) {
node.expanded = !node.expanded;
if (node.children && node.children.length > 0) {
this.found = false;
myJson.forEach(child => {
if (!this.found) {
this.saveStates(child, node);
}
});
}
}
/** recursive loop-function used by this.changeState() to save tree-items expanded-state to the master array */
saveStates(child, clickedChild) {
if (child.id === clickedChild.id) {
child.expanded = clickedChild.expanded;
this.found = true;
return;
} else if (child.children && child.children.length > 0) {
child.children.forEach(c => {
this.saveStates(c, clickedGroup);
});
}
}
- 树形示例中的标准函数我进行了如下更改以使用我的数据:
// checks if datasource for material tree has any children
hasNestedChild = (_: number, nodeData: MyModel) => nodeData.children.length > 0;
// returns children
private _getChildren = (node: MyModel) => node.children;
答案 2 :(得分:0)
this.treeControl.expansionModel.selected
目前为您提供扩展节点,以便您可以保存它们 this.prevExpansionModel = this.treeControl.expansionModel.selected
并应用它们,如下所示:
this.prevExpansionModel.forEach(object => this.treeControl.expand(object));
虽然在这样做之后关闭和再次打开似乎不是abke,所以你必须弄清楚这一点,但也许这会让你更接近你的目标