Learn how to easily truncate and append an ellipsis to content using an Angular directive.
Goals
The goals for our ellipsis directive are:
- A simple attribute directive that can be applied to an element with a specified fixed height.
- Avoid overflowing the text content beyond the specified fixed height.
- If the text is overflowing, remove the necessary text and append an ellipsis until the text fits within the specified height.
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
:
- First, we have a handy
el
property accessor for accessing thenativeElement
property on the injectedElementRef
class instance. Note that the return type for this is a genericHTMLElement
. This is necessary so we have intellisense and type checking when accessing theinnerText
property of the element. - Next, the
innerText
class property is simple astring
in which we will store the original text within the element that the attribute directive is applied to. - In the
constructor()
function we are injecting both theElementRef
class instance as well as theplatformId
using thePLATFORM_ID
injection token. - The directive implements the
AfterViewInit
lifecycle interface and it’s associatedngAfterViewInit()
lifecycle method. Once the view has been initialized, we can truncate the text based on the element’sscrollHeight
andclientHeight
values. We’ll see this below in thetruncate
method. - We’ll invoke the
truncate()
method both after the view has been initialized as well as when the browser window has been resized. - Using the
HostListener()
decorator we can listen for theresize
event to occur on the global window object, and then truncate the text as necessary. This is especially important if the width of the element is not fixed. - Finally, within the
truncate()
method we’ll first verify that we are executing in the context of a browser. Then, we’ll store the initial value of theinnerText
property so that if we need to truncate the text later based on the window being resized we can do so. We then truncate the text and append the ellipsis by comparing the value of the element’sscrollHeight
to theclientHeight
. We’ll continue to remove words until the content fits within the specified height of the element.
Demo
Check out the following stackblitz with an example of the EllipsisDirective
: