Skip to content

Instantly share code, notes, and snippets.

@AitorAlejandro
Forked from Coder-Jedi/read-more.directive.ts
Created November 18, 2022 07:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AitorAlejandro/87a57fd7a34f539d0f101ef86b0693a6 to your computer and use it in GitHub Desktop.
Save AitorAlejandro/87a57fd7a34f539d0f101ef86b0693a6 to your computer and use it in GitHub Desktop.
import { AfterViewInit, Directive, ElementRef, Input, Renderer2 } from '@angular/core';
@Directive({
selector: '[appReadMore]'
})
export class ReadMoreDirective implements AfterViewInit {
@Input() limit : number = 50; //to get the custom text limit
@Input() toggle : boolean = false; //true: 'Read Less' button will be present
txtSpan! : HTMLSpanElement;
btnSpan! : HTMLSpanElement;
listeners : any[] = []; //add event listeners to unsubscribe all at the end
constructor(private el : ElementRef,
private renderer : Renderer2) {}
ngAfterViewInit(): void {
//step 1 ---> change the text in HTML DOM element (<p>, <div>, <span>, <h1>, etc)
let text : string = this.el.nativeElement.innerHTML;
if(text.length > (this.limit)) //perform below logic only when text length exceeds limit
{
this.renderer.setProperty(this.el.nativeElement, 'innerHTML', text.substring(0,this.limit));
//step 2 ---> create txtSpan(remaining text) and btnSpan(Read More button)
this.txtSpan = this.renderer.createElement('span');
this.btnSpan = this.renderer.createElement('span');
//step 3 ---> set initial properties and styles for both span elements
this.renderer.setProperty(this.txtSpan, 'innerHTML', text.substring(this.limit));
this.renderer.setStyle(this.txtSpan, 'display', 'none');
this.renderer.setProperty(this.btnSpan, 'innerHTML', 'Read More');
//below css properties are optional
this.renderer.setStyle(this.btnSpan, 'cursor', 'pointer');
this.renderer.setStyle(this.btnSpan, 'margin-left', '1ch');
this.renderer.setStyle(this.btnSpan, 'text-decoration', 'underline');
//step 4 ---> add onClick handler for 'Read More' button span
if(this.toggle) //case when toggling needs to be enabled
this.listeners.push(this.renderer.listen(this.btnSpan, 'click', () => {
if(this.txtSpan.style.display == 'none') //case when the text is hidden(default case)
{
this.renderer.setStyle(this.txtSpan, 'display', 'inline');
this.renderer.setProperty(this.btnSpan, 'innerHTML', 'Read Less');
}
else //case when the text is visible
{
this.renderer.setStyle(this.txtSpan, 'display', 'none');
this.renderer.setProperty(this.btnSpan, 'innerHTML', 'Read More');
}
}));
else //case when toggling is off (only show text)
this.listeners.push(this.renderer.listen(this.btnSpan, 'click', () => {
this.renderer.setStyle(this.txtSpan, 'display', 'inline');
this.renderer.setStyle(this.btnSpan, 'display', 'none');
}));
//step 5 ---> append both span to the HTML DOM element
this.renderer.appendChild(this.el.nativeElement, this.txtSpan);
this.renderer.appendChild(this.el.nativeElement, this.btnSpan);
}
}
ngOnDestroy(): void {
this.listeners.forEach(val => val());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment