Tree material angular 2 selected state
Solution 1
I managed to develop a working example of what you are trying to achieve. The presentation is basic but it uses a layout identical to your example code. I included a link at the very bottom to my solution. It basically boils down to the below code.
component.ts
// inside of the component class
@ViewChildren(MatTreeNode, { read: ElementRef }) treeNodes: ElementRef[];
hasListener: any[] = [];
oldHighlight: ElementRef;
updateHighlight = (newHighlight: ElementRef) => {
this.oldHighlight && this.renderer.removeClass(this.oldHighlight.nativeElement, 'background-highlight');
this.renderer.addClass(newHighlight.nativeElement, 'background-highlight');
this.oldHighlight = newHighlight;
}
ngAfterViewChecked() {
this.treeNodes.forEach((reference) => {
if (!this.hasListener.includes(reference.nativeElement)) {
console.log('* tick');
this.renderer.listen(reference.nativeElement, 'click', () => {
this.updateHighlight(reference);
});
this.renderer.listen(reference.nativeElement.children.item(0), 'click', () => {
this.updateHighlight(reference);
});
this.hasListener = this.hasListener.concat([ reference.nativeElement ]);
}
});
this.hasListener = this.hasListener.filter((element) => document.contains(element));
console.log('*', this.hasListener.length);
}
component.css
.background-highlight {
background-color: whitesmoke;
}
I positioned most of my logic inside of the ngAfterViewInit
lifecycle hook. This is so I could access the results of the @ViewChild
query. The query returns references to all of the <mat-tree-node></mat-tree-node>
elements in the template. The results are stored in this.treeNodes
as a QueryList.
I iterate across the list. I check to see if the referenced nativeElement
already has its event listeners. The event listeners trigger on mouse click
. The callback updateHighlight
handles the removal and addition of the background-highlight
css class so that it remains unique in the DOM.
I added two event listeners targeting the <mat-tree-node></mat-tree-node>
and its nested <button></button>
element. Clicking both places highlights the tree node all the same.
In updateHighlight
I remove the background-highlight
class from wherever it was previously added (if applicable). Whatever is currently clicked gets the background-highlight
class. A reference to the clicked element replaces the previous value of this.oldHighlight
.
For the sake of performance, I included this.hasListener
. The array stores the <mat-tree-node></mat-tree-node>
elements that have already received their listeners. I can check the array to ensure that I am not needlessly overwriting listeners with each pass of ngAfterViewChecked
.
The last bit of logic keeps this.hasListener
from growing out of control. Any elements no longer attached to the DOM are no longer a concern.
I kept in two console.log
statements because their outputs reflect that the code works beyond highlighting clicked tree nodes.
For any other questions, see the repository: https://github.com/sosmaniac-FCC/mat-tree-node-example/tree/master/src/app/components/example-one . I did import some extra utilities from @angular/core
.
Of course, if I missed the mark anywhere just let me know. I will follow-up the best I can.
Solution 2
There's an easier cleaner way to do this.
All you have to do is add
(click)="activeNode = node" [ngClass]="{ 'background-highlight': activeNode === node }"
to each mat-tree-node
.
Don't forget to add the activeNode
variable to your component.
That's it!
Related videos on Youtube
Bogdan
Updated on June 29, 2022Comments
-
Bogdan almost 2 years
I have a Angular 2 Material Tree when I click a node from the tree I need to have the selected state on that node to change the background color. I have no idea how I can do that. I didn't find nothing in documentation to help me. Here is the html code and a picture that how it should look the tree
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" #matTree [ngStyle]="{ 'color': red}"> <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle matTreeNodePadding> <button mat-icon-button disabled></button> {{node.filename}} </mat-tree-node> <mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding > <button mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.filename" click="onClick()"> <mat-icon class="mat-icon-rtl-mirror"> {{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}} </mat-icon> </button> {{node.filename}} </mat-tree-node> </mat-tree>
-
d11 over 5 yearsNIce BTW - do you know - if it's possible to add branch lines ? .
-
Jony Adamit over 5 yearsNever tried it, but a quick search gave me this
-
BluJ IT about 3 yearsDon't forget the CSS changes for the component as mentioned above in the response from @John
.background-highlight { background-color: whitesmoke; }