Picture of Brian Love wearing black against a dark wall in Portland, OR.

Brian Love

Ellipsis Directive

Learn how to easily truncate and append an ellipsis to content using an Angular directive.

Goals

The goals for our ellipsis directive are:

ElementRef

The first concept we need to understand is Angular’s ElementRef instance when using an attribute directive. We can access this via dependency injection in our attribute directive’s constructor() function.

The nativeElement property on the ElementRef class instance enables us to access the native document object model (DOM) element in the context of the browser. Once we have access to the element, we can determine if the element’s scrollHeight property value exceeds the element’s clientHeight property value.

Platform Specific

It’s important to note that the strategy that we’ll implement here will be platform specific. To clarify, Angular is not just a framework for building single-page applications in the context of a browser. Rather, Angular can be used for building applications in any context, but is most often used in the context of a browser, Node.js, electron for building desktop applications, and either NativeScript or Ionic for building hybrid mobile applications.

In summary, we’ll use the isPlatformBrowser() function that is available in the @angular/common module for verifying that the application is indeed executing in the context of the browser.

The EllipsisDirective

Here is the full source code for the Angular attribute directive:

@Directive({
  selector: '[appEllipsis]'
})
export class EllipsisDirective implements AfterViewInit {
  /** The native HTMLElement. */
  private get el(): HTMLElement {
    return this.elementRef.nativeElement;
  }

  /** The original innerText; */
  private innerText: string;

  constructor(
    private readonly elementRef: ElementRef,
    @Inject(PLATFORM_ID) private readonly platformId
  ) {}

  public ngAfterViewInit(): void {
    this.truncate();
  }

  @HostListener('window:resize')
  private onWindowResize() {
    this.truncate();
  }

  private truncate(): void {
    // verify execution context is the browser platform
    if (!isPlatformBrowser(this.platformId)) {
      return;
    }

    // store the original innerText
    if (this.innerText === undefined) {
      this.innerText = this.el.innerText.trim();
    }

    // reset the innerText
    this.el.innerText = this.innerText;

    // truncate the text and append the ellipsis
    const text = this.innerText.split(' ');
    while (text.length > 0 && this.el.scrollHeight > this.el.clientHeight) {
      text.pop();
      this.el.innerText = `${text.join(' ')}…`;
    }
  }
}

Let’s dive into the the implementation of the EllipsisDirective:

Demo

Check out the following stackblitz with an example of the EllipsisDirective: