Reputation: 385
Is there any way we can detect if the text is overflow in angular controller?
In my CSS I have the following code:
width: calc(100% - 60px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding-top: 5px;
And I want to be able to detect if the text is overflow in the angular controller so I can display the tooltip for it. If the text is not overflow then no need to display the tooltip, which was the reason why I want to be able to detect if the text is overflow in the controller.
Upvotes: 13
Views: 32079
Reputation: 5694
Spent half a day working on this...
There's a codepen solution that uses vanilla/alpine js. I've managed to adapt this to Angular:
import { CommonModule } from '@angular/common';
import { Component, ElementRef, Input, ViewChild } from '@angular/core';
@Component({
selector: 'app-expand-if-ellipsis',
templateUrl: './expand-if-ellipsis.component.html',
styleUrl: './expand-if-ellipsis.component.css',
standalone: true,
imports: [CommonModule],
})
export class ExpandIfEllipsisComponent {
@Input() pslText: string = "";
@ViewChild('textEl') textEl: ElementRef|undefined;
expanded: boolean = false;
ellipsis: boolean = false;
ngAfterViewInit(): void {
setTimeout(()=>{
this.setTruncate();
this.expanded = false;
}, 1)
}
toggleExpanded(expanded: boolean){
this.expanded = !expanded;
}
setTruncate() {
const element = this.textEl?.nativeElement;
if(!element) return;
if (
element.offsetHeight < element.scrollHeight ||
element.offsetWidth < element.scrollWidth
) {
this.ellipsis = true;
} else {
this.ellipsis = false;
}
}
}
<div>
<span
#textEl
[class.ellipsis-4]="!expanded"
>{{pslText}}</span>
<div>
<button
*ngIf="ellipsis"
class="button-to-link text--small"
(click)="toggleExpanded(expanded)"
>{{expanded ? 'Minimise comment' : 'Show full comment'}}</button>
</div>
</div>
.ellipsis-4 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
}
I've tried to create a demo on Stackblitz, but I can't get the darned thing to work with a super simple app. If someone could fix it for me I'd appreciate it. This solution works on my localhost, but some frustrating bugs on stackblitz that I can't figure out.
Upvotes: 0
Reputation: 161
Here's a bit of a cleaner solution I've found for this use-case. Instead of CSS, I used the slice
angular pipe, where the two values mark the start
and end
of the sliced characters.
Slice
and *ngIf
span
follows with a manually written "...
" stringitem.name.length
and having it either be greater or equal to the number of characters allowed from the slice<a *ngFor="let item of items">
{{ item.name | slice: 0 : 20 }}<span *ngIf="item.name.length >=20">...</span>
</a>
I also wanted this to display a tooltip. But I didn't want any other anchors to have a tooltip unless the ellipsis was present (since the tooltip would show the entire name)
mouseover
, uses a ternary operator that triggers an onHover
method IF it has equal or more characters than previous identifiedonHover
method takes in both the $event
and the name (string
) of the itemabsolute
) but binds component variables to [style.top]
and [style.left]
so it appears where mouse event fires(mouseout)
ensures the tooltip is gone when no longer hovering over the element<a
*ngFor="let item of items"
(mouseover)="(item.name.length >= 20) ? onHover($event, item.name) : '' "
(mouseout)="showsTooltip ? (showsTooltip = !showsTooltip) : '' ">
{{ item.name | slice: 0 : 20 }}<span *ngIf="item.name.length >=20">...</span>
</a>
<!-- some other code -->
<div
*ngIf="showsTooltip"
[style.top]="tooltipTopY"
[style.left]="tooltipLeftX"
class="tooltip"
>
{{ tooltipText }}
</div>
export class SomeComponent implements OnInit {
showsTooltip = false;
tooltipText = '';
tooltipTopY!: any;
tooltipLeftX!: any;
// ... other code
onHover(e: any, cardName: string): void {
this.tooltipText = cardName;
if (e) {
this.showsTooltip = true;
this.tooltipTopY = e.clientY + 'px';
this.tooltipLeftX = e.clientX + 'px';
}
}
}
Hope this helps! Grateful for thorough answers that've helped me here; and I find this solution has been pretty clutch for me so far - so just hoping to share where I can!
Upvotes: 2
Reputation: 43
In addition to Mathew's answer.
I applied that JavaScript logic to an angular 2+ implementation using material components. In this example, you can see that the same JS check is utilized to either disable or enable the Material Tooltip if the text was truncated.
<mat-expansion-panel-header
[matTooltipDisabled]="(titleContent.offsetWidth < matpanelTitle.scrollWidth)"
matTooltip="{{recording.alias}}">
<mat-panel-title #matpanelTitle style="white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;">
<span #titleContent>
{{recording.alias}}
</span>
</mat-panel-title>
</mat-expansion-panel-header>
Upvotes: 3
Reputation: 28750
There is no way for angular (or javascript in general) to know whether an element has used the "...". See this very similar question: HTML text-overflow ellipsis detection.
The best you can do is something like this (where you pass the element you care about in):
function isEllipsisActive(e) {
return (e.offsetWidth < e.scrollWidth);
}
Js courtesy that link.
Upvotes: 20