J'utilise un composant de matériau angulaire mat-tree . C'est un composant de Nice avec des fonctionnalités très utiles telles que, sélectionner plusieurs éléments, développer tout/tout réduire . Je n'ai pas trouvé de fonctionnalité de filtrage d'arbre dans aucun de leurs API . Est-ce que quelqu'un a découvert cette fonctionnalité ou fait quelque travail que ce soit pour obtenir un filtre mat-tree?
J'ai résolu le problème en créant une nouvelle source de données (filtrée).
Si je vais expliquer l'exemple de partage du lien, j'ai filtré les données par filter (filterText: string) dans ChecklistDatabase et déclencher l'événement dataChange puis datasource.data modifié par événement géré dans TreeChecklistExample. Ainsi, la source de données a été modifiée.
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);
}
Après avoir passé plusieurs jours sur la même tâche, voici quelques astuces que je peux donner: J'utilise input input pour suivre les entrées de l'utilisateur:
<input matInput class="form-control" (input)="filterChanged($event.target.value)" placeholder="Search Skill" >
Sur ce filtre, j'ai associé un sujet afin de pouvoir y souscrire:
searchFilter: Subject<string> = new Subject<string>();
filterChanged(filter: string): void {
this.searchFilter.next(filter);
}
Pour que tout se passe bien pour l'utilisateur, nous voulons généralement retarder l'exécution de la recherche, ce que vous pouvez faire avec debounceTime.
this.searchFilter.pipe(debounceTime(500), distinctUntilChanged())
.subscribe(value => {
if (value && value.length >= 3) {
this.filterByName(value);
} else {
this.clearFilter();
}
});
Pour effectuer la recherche, je cache et affiche les nœuds à l'aide d'une classe css. Cela se fait directement sur la collection de présentations qui est plate et très facile à filtrer.
treeControl: FlatTreeControl<SkillFlatNode>;
this.treeControl.dataNodes
D'abord, je cache tout et ne montre que ceux qui correspondent aux critères. Enfin, je veux montrer à leurs parents, mais ceci est spécifique à mon arborescence.
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);
});
}
Enfin voici le filtre clair
private clearFilter(): void {
this.treeControl.dataNodes.forEach(x => x.visible = true);
}
Ne faites pas la même erreur que moi et essayez de filtrer la collection d'entrées (this.dataSource.data dans mon cas) car vous perdrez votre sélection ou vous devrez la mapper à la présentation . Voici ma première Les données.
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;
});
Ajoutez d’abord une entrée en tant que filtre dans la vue. Lier l'événement keyup à rxjs
<input type="text" matInput placeholder="search" #filter (keyup)="keyEvent.next($event)" [(ngModel)]="keyword">
Puis interrogez votre serveur afin de filtrer le nœud d’arbre avec le mot clé
this.keyEvent.pipe(
map((e: any) => e.target.value.toLowerCase()),
debounceTime(500),
distinctUntilChanged(),
switchMap((keyword: string) => {
if (keyword && keyword.length > 2) {
return this.yourservice.searchForData(this.entId, keyword);
} else {
return of();
}
})
)
.subscribe((r) => {
this.nestedDataSource.data = r;
this.nestedTreeControl.dataNodes = r;
this.nestedTreeControl.expandAll();
});
Je suis capable de filtrer un arbre en utilisant une récursivité simple. Voici les extraits de code:
La fonction filter()
est appelée sur (keyup)
sur input type="text"
. La fonction cloneDeep
est importée de lodash import * as cloneDeep from 'lodash/cloneDeep';
this.searchString
est la valeur de chaîne pour le texte du filtre.
filter() {
const clonedTreeLocal = cloneDeep(this.clonedTree);
this.recursiveNodeEliminator(clonedTreeLocal);
this.dataSource.data = clonedTreeLocal;
this.treeControl.expandAll();
}
L'arborescence est définie par l'interface
export interface ITreeDataStructure {
Id?: number;
name: string;
type: string;
children?: Array<ITreeDataStructure>;
}
Le filtrage réel est effectué par la fonction 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;
}