13

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.

1

4 Answers 4

20

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.

Sign up to request clarification or add additional context in comments.

Comments

3

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>

Comments

2

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.

Angular Ellipsis with Slice and *ngIf

  • Slice pipe isolates first 20 characters
  • A span follows with a manually written "..." string
  • The ellipsis span is conditional on how many characters are showing using item.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>

Show Tooltip Conditionally

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)

Template
  • With mouseover, uses a ternary operator that triggers an onHover method IF it has equal or more characters than previous identified
  • The onHover method takes in both the $event and the name (string) of the item
  • Tooltip has styling required to appear at mouse coords (absolute) but binds component variables to [style.top] and [style.left] so it appears where mouse event fires
  • The (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>
Component
  • Catches the coordinates from the event object and binds them accordingly
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!

1 Comment

This is one of the best and simplest solutions......Thank You
1

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.

1 Comment

This condition worked for me element.offsetHeight < element.scrollHeight

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.