NashTech Insights

Angular lazy loading directive with IntersectionObserver

Alka Vats
Alka Vats
Table of Contents

Intersection Observer: what is it?

The Intersection Observer API is a relatively new functionality in web browsers that can allow us to listen to events when an element’s visibility on the page changes.

Thanks to Angular’s directives, we can create a reusable way to use this API in a declarative and easy way.
If you want to learn in deep you can refer here. and If you wants to learn about the latest feature of angular, you can refer here

In this blog, we would like to reach a certain part of the viewport, and then load some data specific to that part, or maybe perform some tracking action. So I would observe a specific HTML selector and then do something when that selector comes into view. And that selector could be anywhere on the page, not just at the end, something like this:

So of course, we go for the IntersectionObserver API. Almost all modern browsers now support it, so we should ideally have no problem with a modern website.

Let us once again break down the requirements, one by one.
1) We need a custom directive, which we can place on any HTML element.
2) This directive will accept a callback method as a parameter so that the parent component consuming the directive can decide what to do once the child element comes into view.
3) Tracking should happen only once, so that every time the element comes into view (due to the user scrolling up and down), the data should not be re-fetched. But this is my specific use case, you may choose to do differently.
4) The observer should be disconnected when the element is destroyed.

The directive:

Whenever we place a directive on an element, we get a reference to the consuming element. And to be honest, this is all we need.
Almost the entire logic happens in the constructor since each directive placed on each element creates a new instance of the class.

Let’s understand what is being done:

The Options:

root – this essentially means the relative component against which your component – the one you would like to observe – should intersect. For our use case, this is the entire document.
rootMargin – this would consider if the document has some margin so that the intersection logic would consider that during its calculation.
threshold – this is a value between 0 and 1 (or consider 0 and 100%). A value of 1 means, the API would consider my component to be intersecting with the document only when 100% of the element is in view. You can change this as per your need.

The Intersection callback and The Observer:

For all components we observe, the callback is executed. For our use case, we have only one target – the element on which our directive is placed. We create a new instance  IntersectionObserver and assign it to an observer. This observer observes our component, which is injected into our directive class through elementRef: ElementRef.

So what happens next?

Depending on the threshold value, the entry.isIntersecting evaluates to true or false, and it is then that we need to do something.

And what do we do then?

Our directive takes in a callback as input, and we fire this callback – this.appTrackable?.();

Also, I mentioned before that each directive on each element is a new instance. So we maintain a class-level variable – tracked. And once the intersection logic is satisfied and the callback is fired, we do not need to fire the logic again and again. You could go one step ahead and disconnect the observer itself.

When the component gets destroyed, so does the directive, and you can tap onto the ngOnDestroy method, to disconnect the observer.

ngOnDestroy(): void {
  this.observer?.disconnect();
}

The implementation

The implementation means placing the directive on an element and then passing a callback reference to it.

home.component.html

<app-people [appTrackable]="callback1"></app-people>
<app-place [appTrackable]="callback2"></app-place>

The callback methods include some logic to fire HTTP calls to fetch data for that element, Just remember to bind your callback to the service or class instance, as applicable.

home.component.ts

export class HomeComponent {
  constructor(private readonly data: DataService) {}

  readonly callback1 = this.data.callback.bind(this.data, 'people');
  readonly callback2 = this.data.callback.bind(this.data, 'places');
}

So what are the possibilities?

Well, you can do whatever you want with the callback thingy! But, I would say, tracking for analytics is one very important use case. You can also use this to execute infinite loading on the scroll.

Conclusion:

In this blog, we have learned about the Angular lazy loading directive with IntersectionObserver. It will help you to understand how this works. Let me know in the comments if you can come up with more use cases!

Finally, for more such posts, please follow our LinkedIn page- FrontEnd Competency.

Alka Vats

Alka Vats

Alka Vats is a Software Consultant at Nashtech. She is passionate about web development. She is recognized as a good team player, a dedicated and responsible professional, and a technology enthusiast. She is a quick learner & curious to learn new technologies. Her hobbies include reading books, watching movies, and traveling.

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

%d bloggers like this: