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ó.