如何过滤mat-tree组件Angular Material 6.0.1

Sat*_*tAj 8 tree filter angular-material2 angular angular6

我正在使用垫树角材料组件.这是一个很好的组件,有一些非常有用的功能,如多选,全部展开/全部折叠.我无法在任何API中找到任何树过滤功能.有没有人遇到这个功能或做任何工作来获得mat-tree过滤器?

在此输入图像描述

Ami*_*h B 16

mat-tree 过滤器的 Stackblitz 链接

如果任何人需要在不修改数据源的情况下直观地过滤 mat 树,那么请选择此解决方案。

基本上,这个想法是隐藏不属于搜索字符串的节点。

输入栏

<input [(ngModel)]="searchString" />
Run Code Online (Sandbox Code Playgroud)

调用叶节点的过滤函数(这是在第一个 mat-tree-node 中完成的)

<mat-tree-node
   *matTreeNodeDef="let node"
   [style.display]="
      filterLeafNode(node) ? 'none' : 'block'
   "
   .....
   ......
Run Code Online (Sandbox Code Playgroud)

对叶节点以外的节点调用过滤函数(这是在第二个 mat-tree-node 中完成的)

<mat-tree-node
   *matTreeNodeDef="let node; when: hasChild"
   [style.display]="filterParentNode(node) ? 'none' : 'block'"
   .....
   .....
Run Code Online (Sandbox Code Playgroud)

filterLeafNode 函数

filterLeafNode(node: TodoItemFlatNode): boolean {
   if (!this.searchString) {
     return false
   }
   return node.item.toLowerCase()
     .indexOf(this.searchString?.toLowerCase()) === -1
}
Run Code Online (Sandbox Code Playgroud)

过滤父节点函数

filterParentNode(node: TodoItemFlatNode): boolean {

  if (    
    !this.searchString ||
    node.item.toLowerCase()
     .indexOf(
       this.searchString?.toLowerCase()
     ) !== -1
  ) {
    return false
  }
  const descendants = this.treeControl.getDescendants(node)

  if (
    descendants.some(
      (descendantNode) =>
        descendantNode.item
          .toLowerCase()
          .indexOf(this.searchString?.toLowerCase()) !== -1
    )
  ) {
    return false
  }
  return true
}
Run Code Online (Sandbox Code Playgroud)


小智 5

在完成相同任务几天后,这里提供一些提示:我正在使用输入事件来跟踪用户输入:

<input matInput class="form-control" 
  (input)="filterChanged($event.target.value)" 
  placeholder="Search Skill">
Run Code Online (Sandbox Code Playgroud)

在此过滤器上,我附加了一个主题,因此我可以订阅它:

searchFilter: Subject<string> = new Subject<string>();
filterChanged(filter: string): void {
  this.searchFilter.next(filter);
}
Run Code Online (Sandbox Code Playgroud)

为了使用户使用起来更加顺畅,通常,我们希望延迟您可以执行的搜索执行debounceTime。

this.searchFilter.pipe(debounceTime(500), distinctUntilChanged())
  .subscribe(value => {
    if (value && value.length >= 3) {
      this.filterByName(value);
    } else {
      this.clearFilter();
    }
});
Run Code Online (Sandbox Code Playgroud)

为了执行搜索,我使用css类隐藏并显示了节点。这是直接在扁平且易于过滤的演示文稿集合上完成的。

treeControl: FlatTreeControl<SkillFlatNode>;
this.treeControl.dataNodes
Run Code Online (Sandbox Code Playgroud)

首先,我全部隐藏,然后仅显示符合条件的那些。最后,我想向他们的父母展示,但这是针对我的树形结构的。

private filterByName(term: string): void {
  const filteredItems = this.treeControl.dataNodes.filter(
    x => x.value.DisplayName.toLowerCase().indexOf(term.toLowerCase()) === -1
  );
  filteredItems.map(x => {
    x.visible = false;
  });

  const visibleItems = this.treeControl.dataNodes.filter(
    x => x.value.IsSkill &&
    x.value.DisplayName.toLowerCase().indexOf(term.toLowerCase()) > -1
  );
  visibleItems.map( x => {
    x.visible = true;
    this.markParent(x);
  });
}
Run Code Online (Sandbox Code Playgroud)

最后,这是清除过滤器:

private clearFilter(): void {
  this.treeControl.dataNodes.forEach(x => x.visible = true);
}
Run Code Online (Sandbox Code Playgroud)

不要像我一样犯同样的错误,并尝试过滤输入集合(this.dataSource.data在我的情况下),因为您会丢失选择,或者必须将其映射回演示文稿。这是我的初始数据:

this.treeFlattener = new MatTreeFlattener(
  this.transformer, this._getLevel, this._isExpandable, this._getChildren
);
this.treeControl = new FlatTreeControl<SkillFlatNode>(
  this._getLevel, this._isExpandable
);
this.dataSource = new MatTreeFlatDataSource(
  this.treeControl, this.treeFlattener
);

skillService.dataChange.subscribe(data => {
  this.dataSource.data = data;
});
Run Code Online (Sandbox Code Playgroud)

  • 关键是不要过滤dataSource.data。而是在 dataNodes 上有一个属性来使用 ngClass/ngStyle 驱动显示。 (3认同)

mfa*_*tih 5

我通过创建一个新的数据源(已过滤)解决了这个问题。

突击样本

我将解释共享链接的示例:我使用filter(filterText: string)in 过滤了数据ChecklistDatabase并触发了一个dataChange事件。然后datasource.data由中的已处理事件更改TreeChecklistExample。因此,数据源已被修改。

filter(filterText: string) {
  let filteredTreeData;

  if (filterText) {
    filteredTreeData = this.treeData.filter(
      //There is filter function in the sample
    );
  } else {
    filteredTreeData = this.treeData;
  }

  // file node as children.
  const data = this.buildFileTree(filteredTreeData, '0');

  // Notify the change. !!!IMPORTANT
  this.dataChange.next(data);
}
Run Code Online (Sandbox Code Playgroud)


Kar*_*hik 5

我能够通过使用简单的递归来过滤树。下面是代码片段:

该filter()函数是在 上调用(keyup)的input type="text"。cloneDeep函数是从 lodash 导入的import * as cloneDeep from 'lodash/cloneDeep';

this.searchString 是过滤器文本的字符串值。

  filter() {
    const clonedTreeLocal = cloneDeep(this.clonedTree);
    this.recursiveNodeEliminator(clonedTreeLocal);
    this.dataSource.data = clonedTreeLocal;
    this.treeControl.expandAll();
  }
Run Code Online (Sandbox Code Playgroud)

树结构由接口定义

export interface ITreeDataStructure {
    Id?: number;
    name: string;
    type: string;
    children?: Array<ITreeDataStructure>;
}
Run Code Online (Sandbox Code Playgroud)

实际的过滤是由函数完成的 recursiveNodeEliminator

recursiveNodeEliminator(tree: Array<ITreeDataStructure>): boolean {
    for (let index = tree.length - 1; index >= 0; index--) {
      const node = tree[index];
      if (node.children) {
        const parentCanBeEliminated = this.recursiveNodeEliminator(node.children);
        if (parentCanBeEliminated) {
          if (node.name.toLocaleLowerCase().indexOf(this.searchString.toLocaleLowerCase()) === -1) {
            tree.splice(index, 1);
          }
        }
      } else {
        // Its a leaf node. No more branches.
        if (node.name.toLocaleLowerCase().indexOf(this.searchString.toLocaleLowerCase()) === -1) {
          tree.splice(index, 1);
        }
      }
    }
    return tree.length === 0;
  }
Run Code Online (Sandbox Code Playgroud)

  • 伟大的!在具有虚拟滚动和数千个节点的平面树中像魅力一样工作...... (2认同)