Angular 19.x library to monitor when elements are visible in the DOM. When you have a huge list of components, this is more performant than other libraries because it keeps the number of observers to a minimum. It uses IntersectionObserver to do the work.
If you only care about when elements are resized, including resize events due to browser window size changing, look at ngx-resize-observer.
If you want to be notified when DOM elements change properties, ngx-mutation-observer would be a good pick.
There's a live demo over at CodeSandbox.io.
Install like other Angular libraries. First run a command to download the module.
npm install ngx-visibility
Next, add the module to your project.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
// Import the module
import { NgxVisibilityModule } from 'ngx-visibility';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent, ItemComponent, NgxVisibilityDirective],
// Include the module.
imports: [BrowserModule, FormsModule, NgxVisibilityModule],
providers: [NgxVisibilityService],
bootstrap: [AppComponent]
})
export class AppModule {}
Finally, you leverage the service directly or use some directives for common uses.
Load an image or a background image when the element is visible.
<img src="myImage.png" ngxVisibilityLazyLoad />
<img srcset="myImage.png 1x, betterImage.png 2x" ngxVisibilityLazyLoad />
<div backgroundImage="myImage.png" style="height: 100px; width: 82px" ngxVisibilityLazyLoad></div>
Supports src
and srcset
for images, backgroundImage
for all HTML elements. It's highly recommended that you set at least a placeholder size (possibly with min-height
and min-width
) for elements. Once the item is flagged visible, the observer is removed and the item stays visible.
Configuration is allowed through ngxVisibilityAnchorDirective
, ngxVisibilityMargin
and ngxVisibilityThreshold
, which are discussed below.
Emit a boolean when an item becomes visible or is hidden from view.
<my-component (ngxVisibility)="updateVisibility($event)"></my-component>
Listener is automatically added and removed by the directive.
Configuration is allowed through ngxVisibilityAnchorDirective
, ngxVisibilityMargin
and ngxVisibilityThreshold
, which are discussed below.
This service maintains the list of observers and calls callbacks when items become visible or are invisible.
import { Component, ElementRef, OnDestroy, OnInit } from '@angular/core';
import { NgxVisibilityService } from 'ngx-visibility';
@Component({
selector: 'my-component'
})
export class MyComponent implements OnDestroy, OnInit {
constructor(
private readonly ngxVisibilityService: NgxVisibilityService,
private readonly elementRef: ElementRef
) {}
ngOnInit() {
this.ngxVisibilityService.observe(
// The native element reference
this.elementRef.nativeElement,
// A callback that is called whenever the element crosses
// a threshold. When you use thresholds, tracking how many
// have been crossed is up to you.
isVisible => {
console.log('I am now', isVisible ? 'visible' : 'hidden');
},
// The configuration object is optional. Look at
// IntersectionObserver for what these values mean.
// The config is of type IntersectionObserverInit.
{
// The viewport native element to use as our window.
// Defaults to `window`.
root: null,
// How far outside the viewport to extend. Useful for
// loading items that are almost going to be seen.
// Negative margins will not load items until they
// progress that far into the view window.
// Must be specified in pixels or percent and use
// the typical CSS margin formats.
rootMargin: '40px',
// Thresholds. Default is [ 0 ]. Can be either a number or
// an array of thresholds. Values are from 0 (not visible)
// to 1 (completely visible).
threshold: [ 0, .33, .66 ]
}
);
}
ngOnDestroy() {
this.ngxVisibiltyService.unobserve(this.elementRef.nativeElement);
}
}
Used to flag a viewport instead of using the whole window. When using this directive, the component must also use the ngxVisibility
or ngxVisibilityLazyLoad
directive, otherwise this directive has no effect. Really, that's not too bad but it is a little wasteful because resources will be loading before you want them.
<div ngxVisibilityAnchorDirective style="overflow: scroll; height: 40px; width: 40px">
<div *ngFor="let item in itemList" ngxVisibility="setItemVisibility(item, $event)">
{{ item.name }} is visible? {{ item.visibility }}
</div>
</div>
This attribute is used with ngxVisibility
or ngxVisibilityLazyLoad
in order to set the margin when observing that element. Margins are specified as per the CSS properties and must be measured in pixels or percent.
<!-- Load when it is within 100px of being seen. -->
<img src="cool-image.png" ngxVisibilityLazyLoad ngxVisibilityMargin="100px" />
<!-- Load if the element is within half of a screen away from being seen. -->
<div (ngxVisibility)="setVisibility($event)" ngxVisibilityMargin="50%" />
Sets up one or more thresholds when combined with ngxVisibility
or ngxVisibilityLazyLoad
. It accepts an array, a number, or a string that will be converted to a number. Numbers need to be within the range of 0 to 1.
<div ngxVisibility="setVisibility($event)" ngxVisibilityThreshold="1">...content...</div>
<div ngxVisibility="setVisibility($event)" [ngxVisibilityThreshold]="[ 0, .5 ]">...content...</div>
This project is licensed under an MIT license.