From backend to frontend
A long time ago in a galaxy far, far away…
In this article, I will share my journey of developing the TOC component and how it sparked my interest in frontend development.
As a backend engineer, my primary focus has always been on developing robust and efficient systems that power web applications.
However, recently I decided to make blog as my pet project where I developed a table of contents (TOC) component for an Angular application.
This experience opened up a whole new world of possibilities and challenges that I had never encountered before.
In our quest to create an engaging TOC component, we will harness some of Angular”s most powerful features, such as ViewChild
, ElementRef
, and dependency injection.
Let”s explore the main sections of our TOC component:constructor,
ngAfterViewInit
, and IntersectionObserver Callback
.
The constructor sets the stage for our TOC component.
constructor(@Inject(DOCUMENT) private document: Document) {
// ...
}
We also initialize the IntersectionObserver
, a key player in detecting when an element enters or exits the viewport.
This functionality is crucial for updating the TOC as users scroll through the content.
ngAfterViewInit: Lifecycle Hook and DOM Manipulation
The ngAfterViewInit
method is an Angular lifecycle hook that gets called after the view is initialized.
At this point, the DOM elements are rendered and ready for manipulation. In this method, we first iterate through the tocTargetElementRef
array, which holds the heading elements.
For each heading, we create a newTocElement
object and push it to the tocList
array.
this.tocTargetElementRef.forEach((el) => {
this.tocList?.push({
id: el.id,
lvl: parseInt(el.localName.charAt(1)),
name: el.textContent ?? ''''
});
});
Next, we iterate through all elements with an id attribute within the toc-target
div, observing them using the IntersectionObserver
instance.
This process ensures that we can monitor the headings as they enter and exit the viewport.
this.document.querySelectorAll(''div#toc-target *[id]'').forEach((section) => {
this.intersectionObserver?.observe(section);
});
IntersectionObserver Callback: Dynamic TOC Updates
The IntersectionObserver
callback function is where the magic happens is triggered when the observed elements
intersect with the viewport, this callback allows us to dynamically update the TOC in response to user interactions.
- We begin by iterating through the entries and checking if they intersect with the viewport.
- If an entry is intersecting, we add the
toc-active
class to the corresponding TOC element. If not, we remove the toc-active class. - We then identify the first and last intersecting elements and calculate their positions.
- Finally, we update the SVG path element”s d attribute to connect the active TOC items, adding a visually appealing touch to our component.
const intersectionObserverCallback = (entries) => {
entries.forEach((el) => {
const tocElement = this.document.getElementById(''toc-'' + el.target.id);
if (el.isIntersecting) {
tocElement?.classList.add(''toc-active'');
} else {
tocElement?.classList.remove(''toc-active'');
}
});
const intersected = this.document.getElementsByClassName(''toc-active'');
if (intersected.length === 0) return;
const firstRect = (intersected[0] as HTMLElement).getBoundingClientRect();
const lastRect = (
intersected[intersected.length - 1] as HTMLElement
).getBoundingClientRect();
const d = `M ${firstRect.left} ${firstRect.top + firstRect.height - 25} L ${
lastRect.left
} ${lastRect.top + lastRect.height}`;
this.tocPathEl.nativeElement.setAttribute(''d'', d);
};
Conclusion
By leveraging Angular’s powerful features, we”ve crafted a dynamic and interactive TOC component that listens for viewport changes and updates the TOC items accordingly.
In conclusion, my foray into frontend development through the creation of a table of contents component was nothing short of eye-opening.
As a backend engineer, I had never fully appreciated the intricacies and nuances of designing and implementing user interfaces.
However, this project challenged me to think outside of my comfort zone and explore new avenues of programming.
Through this experience, I discovered that frontend development is just as exciting and rewarding as backend development.
Who knows what other surprises and opportunities await me in the world of programming? One thing is for sure - I am ready to embrace them with open arms.