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>
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!
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.
// 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);
}
.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With