树:更新树时如何保持打开状态

时间:2018-11-13 11:30:29

标签: angular angular-material2

当我将新数据设置为this.dataSource.data时,我需要保持树节点处于打开/关闭状态。新数据与旧数据非常相似-仅添加或删除了一个或几个最低级别的节点。

我的想法是将节点扩展记录到ReplaySubject并重播扩展队列。它应该工作,但是这是非常丑陋的方式。

我希望这里有解决我问题的更优雅的方法。

3 个答案:

答案 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,所以你必须弄清楚这一点,但也许这会让你更接近你的目标