show Tooltip only when the ellipsis is active
Based on the Romain Deneau answer I created a small directive
@Directive({
selector: '[matTooltip][appShowIfTruncated]'
})
export class ShowIfTruncatedDirective implements OnInit {
constructor(
private matTooltip: MatTooltip,
private elementRef: ElementRef<HTMLElement>
) {
}
public ngOnInit(): void {
// Wait for DOM update
setTimeout(() => {
const element = this.elementRef.nativeElement;
this.matTooltip.disabled = element.scrollWidth <= element.clientWidth;
});
}
}
You can use it a little bit easier
<td mat-cell [attr.id]="hospital.organizational_id + '_hospitalname'" *matCellDef="let hospital">
<div id="hospital_name" class="truncate" [matTooltip]="hospital.organization_name" appShowIfTruncated>
{{hospital.organization_name}}
</div>
</td>
Overflow of an element can be detected in JavaScript with this helper, using Angular ElementRef
and a formula from this answer:
function isTextTruncated(element: ElementRef): boolean {
const e = element.nativeElement;
return e.scrollWidth > e.clientWidth;
}
Then, in your component, use it referencing the element with a "@ViewChild
" property:
@ViewChild('hospitalName') hospitalNameElement: ElementRef;
isHospitalNameTruncated(): boolean {
return isTextTruncated(this.hospitalNameElement);
}
Finally, in the template, add the identifier #hospitalName
and call isHospitalNameTruncated()
to customize the tooltip text:
<td mat-cell [attr.id]="hospital.organizational_id + '_hospitalname'"
*matCellDef="let hospital">
<div id="hospital_name" #hospitalName class="truncate"
[matTooltip]="isHospitalNameTruncated() ? hospital.organization_name : null ">
{{hospital.organization_name}}
</div>
</td>
Another improvement; Egor's answers is beautiful but unfortunately ngOnInit
might not be enough. Examples:
- When the element surrounding
[matTooltip]
is resizeable - When the text itself can be changed dynamically
- When CSS selectors change the element padding/font-weight/font-size etc. and as a result truncates the text after initiation
Therefor the result is to bind to mouseenter
(At that point, setTimeout
becomes redundant):
import { Directive, ElementRef, HostListener } from '@angular/core';
import { MatTooltip } from '@angular/material';
@Directive({
selector: '[matTooltip][showIfTruncated]'
})
export class ShowIfTruncatedDirective {
constructor(
private matTooltip: MatTooltip,
private elementRef: ElementRef<HTMLElement>
) {}
@HostListener('mouseenter', ['$event'])
setTooltipState() {
const element = this.elementRef.nativeElement;
this.matTooltip.disabled = element.scrollWidth <= element.clientWidth;
}
}