web-dev-qa-db-fra.com

Comment filtrer un composant mat-tree Angular Matériel 6.0.1

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?

 enter image description here

5
SatAj

J'ai résolu le problème en créant une nouvelle source de données (filtrée). 

échantillon stackblitz

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);
}
3
mfatih

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;
    });
1
ganelon

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();
});
0
steamfood

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;
  }
0
Karthik