Saltar al contenido

Cómo filtrar un componente mat-tree Angular Material 6.0.1

Luego de investigar con especialistas en la materia, programadores de varias ramas y profesores dimos con la respuesta al dilema y la compartimos en esta publicación.

Solución:

Después de pasar varios días en la misma tarea, aquí hay algunos consejos que puedo dar: Estoy usando el evento de entrada para seguir la entrada del usuario:


En este filtro adjunté un asunto para poder suscribirme:

searchFilter: Subject = new Subject();
filterChanged(filter: string): void 
  this.searchFilter.next(filter);

Para que sea sencillo para el usuario, por lo general, queremos retrasar la ejecución de la búsqueda que puede hacer con debounceTime.

this.searchFilter.pipe(debounceTime(500), distinctUntilChanged())
  .subscribe(value => 
    if (value && value.length >= 3) 
      this.filterByName(value);
     else 
      this.clearFilter();
    
);

Para realizar la búsqueda, oculto y muestro los nodos usando una clase css. Esto se hace directamente en la colección de presentación, que es plana y muy fácil de filtrar.

treeControl: FlatTreeControl;
this.treeControl.dataNodes

Primero, escondo todo y luego muestro solo aquellos que coinciden con los criterios. Finalmente, quiero mostrar a sus padres, pero esto es específico para mi estructura de árbol.

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);
  );

Finalmente, aquí está el filtro claro:

private clearFilter(): void 
  this.treeControl.dataNodes.forEach(x => x.visible = true);

No cometa el mismo error que yo e intente filtrar la colección de entrada (this.dataSource.data en mi caso) porque perderá su selección o tendrá que volver a asignarla a la presentación. Aquí están mis datos iniciales:

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

skillService.dataChange.subscribe(data => 
  this.dataSource.data = data;
);

Resolví el problema creando una nueva fuente de datos (filtrada).

muestra de apilamiento

Explicaré el ejemplo del enlace compartido: filtré los datos con filter(filterText: string) en ChecklistDatabase y desencadenó un dataChange evento. Entonces datasource.data fue cambiado por un evento manejado en TreeChecklistExample. Por lo tanto, la fuente de datos ha sido modificada.

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);

Puedo filtrar un árbol usando recursividad simple. A continuación se muestran los fragmentos de código:

Él filter() se llama a la función (keyup) de input type="text". cloneDeep la función se importa de lodash import * as cloneDeep from 'lodash/cloneDeep';

this.searchString es el string valor para el texto del filtro.

  filter() 
    const clonedTreeLocal = cloneDeep(this.clonedTree);
    this.recursiveNodeEliminator(clonedTreeLocal);
    this.dataSource.data = clonedTreeLocal;
    this.treeControl.expandAll();
  

La estructura de árbol está definida por la interfaz.

export interface ITreeDataStructure 
    Id?: number;
    name: string;
    type: string;
    children?: Array;

El filtrado real se realiza mediante la función recursiveNodeEliminator

recursiveNodeEliminator(tree: Array): 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;
  

Recuerda que puedes comunicar esta noticia si te ayudó.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *