L’albero materiale angolare, il MatTree, è il controllo ideale per la visualizzazione dei dati gerarchici. Non solo può rappresentare un numero variabile di livelli, ma ogni elemento nell’albero può possedere un diverso numero di bambini e livelli. Nella 2a rata del Crea un albero a selezione multipla nidificato con in Angular serie, abbiamo utilizzato MatTree per creare un’alternativa all’HTML SELEZIONARE controllo più adatto per lavorare con i dati gerarchici. Come parte di quel tutorial di sviluppo web, abbiamo imparato come recuperare i nodi selezionati usando il NestedTreeControl getDiscendenti() metodo. Come vedremo nell’articolo di oggi, lo stesso metodo può aiutarci a filtrare i nodi in base a una serie di condizioni al fine di limitare i nodi visibili a quelli che sono:
- selezionato (vale a dire, selezionato)
- corrisponde a un determinato criterio di ricerca
Per raggiungere entrambi gli obiettivi di cui sopra, eseguiremo il refactoring del file Demo albero a selezione multipla nidificato dal suddetto articolo aggiungendo a Mostra gli elementi selezionati attivare/disattivare il controllo così come a Filtro casella di testo.
Nascondere gli elementi non selezionati con la visualizzazione CSS
Il filtraggio dei nodi si ottiene al meglio utilizzando una combinazione di codice TypeScript e condizioni del modello piuttosto che mutare la struttura dei dati sottostante. Per farlo, possiamo usare il CSS Schermo proprietà per mostrare o nascondere un determinato nodo. Ma, prima di arrivare a questo, aggiungiamo il controllo di attivazione/disattivazione nel modello:
<p> <mat-slide-toggle class="toggle-show-only-selected" [(ngModel)]="showOnlySelected" >Show only selected</mat-slide-toggle> </p> <mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="example-tree">
Grazie all’associazione a due vie, lo stato del controllo a levetta si riflette immediatamente nel showSelectedOnly valore della variabile:
export class TreeNestedOverviewExample { public showOnlySelected = false; // ...
Possiamo quindi impostare ogni nodo Schermo proprietà utilizzando l’associazione di proprietà Angular.
Per i nodi foglia:
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle [style.display]="showOnlySelected && !node.selected ? 'none' : 'block'" >
Per i nodi radice:
<mat-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodeToggle [style.display]="showOnlySelected && !(node.selected || node.indeterminate) ? 'none' : 'block'" >
Inizializzazione del showOnlySelected variabile a falso mette il cursore di attivazione/disattivazione in posizione off e mostra tutti i nodi per impostazione predefinita:
Facendo scorrere l’interruttore sulla posizione on ora si nascondono tutti i nodi non selezionati (cioè non selezionati):
Leggere: Crea un albero a selezione multipla nidificato in angolare
Filtraggio dei nodi per criteri di ricerca con TypeScript e CSS
Devi ammettere che la prima parte di questo tutorial è stata abbastanza semplice. Questa sezione è un po’ più sostanziosa. Lo stesso approccio di combinazione del codice TypeScript con le condizioni del modello continuerà a servirci bene. Questa volta, tuttavia, sarà necessaria una logica TypeScript per determinare se un nodo deve essere nascosto o visibile.
Con questo in mente, iniziamo aggiungendo il controllo del filtro al modello:
<p> <label>Filter by: <input [(ngModel)]="searchString" /> </label> <mat-slide-toggle class="toggle-show-only-selected" [(ngModel)]="showOnlySelected" >Show only selected</mat-slide-toggle> </p>
Questa volta chiameremo il nascondiNodoFoglia() e hideParentNode() metodi per determinare se mostrare o nascondere il nodo in base a stringa di ricerca.
Per i nodi foglia:
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle [style.display]="showOnlySelected && !node.selected || hideLeafNode(node) ? 'none' : 'block'" >
Ho spesso affermato che le variabili sono di gran lunga preferibili alle chiamate ai metodi nelle espressioni del modello perché queste ultime verranno invocate numerose volte ogni volta che l’utente interagisce con un elemento del nodo. Tuttavia, ci sono momenti in cui un metodo può essere la scelta migliore. In questo caso, il fattore decisivo è quello nascondiNodoFoglia() e hideParentNode() riceverà il nodo come argomento, consentendo loro di verificarne il valore rispetto a stringa di ricerca. In ogni caso, ci sono modi per ridurre al minimo il numero di chiamate di metodo, come vedremo più avanti.
Ecco il markup dell’elemento del nodo radice aggiornato:
<mat-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodeToggle [style.display]="showOnlySelected && !(node.selected || node.indeterminate) || hideParentNode(node) ? 'none' : 'block'" >
Esistono molti modi per verificare se una stringa contiene una determinata sottostringa; un modo per eseguire un test senza distinzione tra maiuscole e minuscole consiste nell’utilizzare un’espressione regolare o un’espressione regolare. Stiamo usando il costruttore in modo da poter usare il stringa di ricerca come il modello:
public hideLeafNode(node: VehicleNode): boolean { return this.showOnlySelected && !node.selected ? true : new RegExp(this.searchString, 'i').test(node.name) === false; }
Si noti che dobbiamo ancora tenere conto del fatto che il nodo potrebbe essere già nascosto dal Mostra solo selezionato filtro. In tal caso, il metodo dovrebbe restituire vero senza nemmeno cercare il stringa di ricerca.
Poiché i modelli RegEx possono contenere una miriade di caratteri speciali, sarebbe probabilmente saggio limitare i caratteri consentiti nell’input di testo a quelli dei valori dei nodi, ad esempio lettere, numeri e spazi, se si trattasse di un’applicazione di produzione.
Nascondere un nodo padre dipende dal fatto che tutti i suoi nodi figli contengano o meno il file stringa di ricerca (cioè, sono nascosti). Per fare ciò, raccoglieremo tutti i figli foglia del nodo e li faremo scorrere attraverso il nascondiNodoFoglia() metodo:
public hideParentNode(node: VehicleNode): boolean { return this.treeControl .getDescendants(node) .filter(node => node.children == null || node.children.length === 0) .every(node => this.hideLeafNode(node)); }
Ecco una schermata del filtro di ricerca in azione:
Leggere: Codifica TypeScript al di fuori delle applicazioni angolari
Limitare le invocazioni del metodo hide*Node()
Come accennato in precedenza, fare affidamento sui metodi per risolvere le condizioni dei modelli può essere un vero e proprio macello di risorse. Per questo motivo, dovresti sempre mirare a mantenere il numero di chiamate al metodo al minimo indispensabile combinando gli operatori di confronto in modo tale che il metodo sia l’ultimo operando della catena. Nel caso del nascondiNodoFoglia() e hideParentNode() metodi, devono essere richiamati solo quando il testo del filtro immette – o il stringa di ricerca – contiene un valore. Con un piccolo aiuto da JavaScript falsitàpossiamo semplicemente aggiungere il stringa di ricerca alle condizioni del modello:
//child nodes (showOnlySelected || this.searchString) && hideLeafNode(node) ? 'none' : 'block'" //parent nodes [style.display]="(showOnlySelected && !(node.selected || node.indeterminate)) || this.searchString && hideParentNode(node) ? 'none' : 'block'"
C’è una demo del codice di oggi su stackblitz.
Conclusione
In effetti, ci sono molti modi in cui gli sviluppatori Web possono filtrare i nodi di un MatTree. I due tipi di filtraggio che abbiamo esplorato qui oggi sono solo un paio dei più comuni. Abbiamo anche ignorato eventuali azioni aggiuntive che potrebbero accompagnare un’operazione di filtro. Nel prossimo articolo, daremo un’occhiata a due di questi. Entrambi relativi al filtraggio delle stringhe di ricerca, espanderemo i nodi che contengono la stringa di ricerca ed evidenzieremo la sottostringa corrispondente nelle etichette dei nodi.
Per saperne di più Tutorial per lo sviluppo web di CSS (Cascading Style Sheets)..