如何使用负载数据按需制作树形视图?

时间:2019-06-03 13:29:48

标签: angular typescript angular-material

如何使树按需加载数据?我已经后端通过哪个方法为我返回了根节点,并通过父母id向我返回了父母的孩子。我想在树上单击节点并加载树数据,然后为我绘制带有子项的新分支,等等。我不知道这棵树有多深。如何用mat-tree实现它?我尝试了递归函数* ngFor,但不适用于mat-tree。我想要类似link的东西,但没有任何外部库

1 个答案:

答案 0 :(得分:1)

好吧,我创建了具有两个功能的服务

getRootNodes(){}

getChildren(node:any){}

getRootNodes,返回第一级root。

getChildren(nodes:any),返回“孩子”。但是,不仅返回字符串数组,而且使它返回具有属性“ isExpandable”的对象数组。对于材料树,必须知道孩子何时生孩子

下一个更改是在DinamicDataSource中使用我们的服务。我们的toggleNode必须使用该服务。如果!expands是setTimeOut下的代码,那么,我们当然不需要setTimeOut。

如果expand = true,我们将调用该服务并订阅数据。在setTimeOut下INTO订阅代码。

请注意,在两种情况下,我们都需要调用this.dataChange.next(this.data)

toggleNode(node: DynamicFlatNode, expand: boolean) {
    const index = this.data.indexOf(node);
    if (!expand)
    {
      let count = 0;
        for (let i = index + 1; i < this.data.length
          && this.data[i].level > node.level; i++, count++) {}
        this.data.splice(index + 1, count);
        this.dataChange.next(this.data);
    }
    else
    {
    node.isLoading = true;
    this.dataService.getChildren(node.item).subscribe(children=>{
      if (!children || index < 0) { // If no children, or cannot find the node, no op
        node.isLoading = false;

        return;
      }
      if (expand) {
        const nodes = children.map(obj =>
          new DynamicFlatNode(obj.name, node.level + 1, obj.isExpandable));
        this.data.splice(index + 1, 0, ...nodes);
      }
      node.isLoading = false;
      // notify the change
      this.dataChange.next(this.data);

    })
    }
  }

最后一个更改是传递给ngOnInit TreeDynamicExample中的构造函数

ngOnInit()
  {
    this.treeControl = new FlatTreeControl<DynamicFlatNode>(this.getLevel, this.isExpandable);
    this.dataSource = new DynamicDataSource(this.treeControl, this.dataService);
    this.dataService.getRootNodes().subscribe(res=>{
      this.dataSource.data = res.map(name => new DynamicFlatNode(name, 0, true));
    })
  }

请注意,在将this.dataSourceData等同于DynamicFlatNode之前,我们需要获取数据并将其放入订阅

更新:使DinamicData源神秘化。

嗯,要了解树形结构,我们可以看一下DynamicData Source中的“数据”。这些数据只是具有以下属性的对象数组:item,level,expandable和loading。所以,看起来像

[
{item: "Fruits",level:0,expandable:true,isLoading:false},
{item: "Apple",level:1,expandable:true,isLoading:false},
{item: "Orange",level:1,expandable:false,isLoading:false},
{item: "Bannana",level:1,expandable:false,isLoading:false},
{item: "Vegetables",level:0,expandable:true,isLoading:false}
]

是的,这只是一个简单的数组。但这是一个有序的数组。因此,我们可以在DinamicDataSource中创建一个功能addNode,例如

  addSubNode(index:number,name:string,isExpandable:boolean)
  {
     const node=this.data[index];
     const dfn={item: name,
         level:node.level+1,
         expandable:isExpandable,
         isLoading:false}
     this.data.splice(index + 1, 0, ...[dfn]);
     this.dataChange.next(this.data);
  }

  addNode(index:number,name:string,isExpandable:boolean)
  {
     const node=this.data[index];
     const dfn={item: name,
         level:node.level,
         expandable:isExpandable,
         isLoading:false}
     this.data.splice(index + 1, 0, ...[dfn]);
     this.dataChange.next(this.data);
  }

  changeNode(index:number,name:string)
  {
     this.data[index].item=name;
  }

看到,在更改数组后-添加一个节点/子节点,我们需要调用this.dataChange.next(this.data),因为拼接可以更改数组的“内容”,但不能更改数组本身。我们还可以做一些“ bizarro”作为

 this.data=[...this.data]

但是Angular Material的成员使我们的生活变得轻松,我们可以使用.next(这是因为数据实际上不是数组,而是BehaviorSubject的值)

我希望该声明消除动态树的“魔力”。我forked the stackblitz添加树形简单按钮以添加节点,添加子节点并更改节点