Search code examples
material-uiangular-materialtreeviewmaterial-tableangular-material-table

Updating data doesnt expand the data tree inside material-table


Im trying to build a table with nested tree folder inside.

When trying to add nested data into the datasource data the structure will not updated and will not toggle anymore.

Code below:

https://stackblitz.com/edit/angular-table-tree-example-k2zqmt?file=app%2Ftable-basic-example.ts&file=app%2Ftable-basic-example.html,app%2Ftable-basic-example.ts

Environment

Angular:
Material Table
Material tree system

Solution

  • These are the things that are happening when logNode method is called

    • The item is getting added but the treeControl.toggle method does not work anymore.
    • When you are assigning a new dataset to the dataSource all the nodes get reset and the tree closes, so this.treeControl.toggle is trying to toggle a node that does not exist.
    • You need to find the node to be toggled from the list you get from treeControl.dataNodes

    I would suggest having the toggle code in a separate method and adding a node code in a separate method, and a separate button to add the node.

    The below code should work for your scenario, also remove this line from your HTML, (click)="treeControl.toggle(data)"

    
    interface ExampleFlatNode {
      expandable: boolean;
      RoleName: string;
      Access: boolean;
      level: number;
      CatId: number;
    }
    
    private transformer = (node: FoodNode, level: number) => {
      return {
        expandable:
          !!node.CategoryPermissions && node.CategoryPermissions.length > 0,
        RoleName: node.RoleName,
        Access: node.Access,
        level: level,
        CatId: node.CatId,
      };
    };
    
    tempNodes = []
    
    constructor() {
      this.dataSource.data = TREE_DATA;
    }
    
    logNode(clickedNode) {
    
        this.tempNodes = [];
    
        this.treeControl.dataNodes.forEach((node) =>
          this.tempNodes.push({
            ...node,
            expanded: this.treeControl.isExpanded(node),
          })
        );
    
      if (!this.treeControl.isExpanded(clickedNode)) {
        const temp = {
          Access: true,
          RoleName: 'test 1 2',
          CatId: 113,
        };
    
        const clickedNodeIdx = this.treeControl.dataNodes.findIndex(
          (node: any) =>
            node.CatId === clickedNode.CatId &&
            node.RoleName === clickedNode.RoleName &&
            node.level === clickedNode.level
        );
    
        const childIdx = 1;
    
        let child;
    
        if (clickedNode.level === 0) {
          child =
            this.dataSource.data[clickedNodeIdx].CategoryPermissions[childIdx];
        } else {
          this.dataSource.data.forEach(
            (item) => (child = this.findDataSource(item, clickedNode))
          );
        }
    
        child.CategoryPermissions.push(temp);
    
        this.dataSource.data = this.dataSource.data;
    
        const addedNode = this.treeControl.dataNodes.find(
          (node: any) =>
            node.CatId === temp.CatId && node.RoleName === temp.RoleName
        );
    
        this.expandParent(addedNode);
        this.setPreviousState();
    
      } else {
        this.treeControl.collapse(clickedNode);
      }
    }
    
    findDataSource(item, node) {
      if (item.RoleName === node.RoleName) {
        return item;
      } else if (item.CategoryPermissions) {
        let matchedItem;
    
        item.CategoryPermissions.forEach((e) => {
    
          const temp = this.findDataSource(e, node);
          if (temp) {
            matchedItem = temp;
          }
        });
    
        return matchedItem;
      }
    }
    
    setPreviousState() {
      for (let i = 0, j = 0; i < this.treeControl.dataNodes.length; i++) {
        if (
          this.tempNodes[j] &&
          this.treeControl.dataNodes[i].RoleName === this.tempNodes[j].RoleName &&
          this.treeControl.dataNodes[i].CatId === this.tempNodes[j].CatId &&
          this.treeControl.dataNodes[i].level === this.tempNodes[j].level
        ) {
          if (this.tempNodes[j].expanded) {
            this.treeControl.expand(this.treeControl.dataNodes[i]);
          }
          j++;
        }
      }
    }
    
    expandParent(node: ExampleFlatNode) {
      const { treeControl } = this;
      const currentLevel = treeControl.getLevel(node);
    
      const index = treeControl.dataNodes.indexOf(node) - 1;
    
      for (let i = index; i >= 0; i--) {
        const currentNode = treeControl.dataNodes[i];
    
        if (currentLevel === 0) {
          this.treeControl.expand(currentNode);
          return null;
        }
    
        if (treeControl.getLevel(currentNode) < currentLevel) {
          this.treeControl.expand(currentNode);
          this.expandParent(currentNode);
          break;
        }
      }
    }