src/components/sq-infinity-scroll/sq-infinity-scroll.component.ts
Represents the SqInfinityComponent, a component for infinite scrolling.
Example :<sq-infinity-scroll [length]="totalItems" [hasMore]="hasMoreData" [loading]="isLoading" (scrolledEmitter)="loadMoreItems()">
<!-- Content Here -->
</sq-infinity-scroll>
AfterViewInit
AfterContentChecked
OnDestroy
selector | sq-infinity-scroll |
styleUrls | ./sq-infinity-scroll.component.scss |
templateUrl | ./sq-infinity-scroll.component.html |
Properties |
|
Methods |
Inputs |
Outputs |
constructor(documentImported: Document, getWindow: GetWindow)
|
||||||||||||
Creates an instance of SqInfinityComponent.
Parameters :
|
elementToScrollId | |
Type : string
|
|
The ID of the element to scroll (if using a custom scrolling element). |
endMessage | |
Type : string
|
|
The message to display when reaching the end of the list. |
hasMore | |
Type : boolean | string
|
|
Default value : true
|
|
Indicates whether there are more items to load. |
length | |
Type : number
|
|
Default value : 0
|
|
The total number of items in the list. |
loaderColor | |
Type : string
|
|
The color of the loader. |
loading | |
Type : boolean
|
|
Indicates whether data is currently being loaded. |
scrolledEmitter | |
Type : EventEmitter<void>
|
|
Event emitter for when the user scrolls to trigger loading more items. |
ngAfterContentChecked |
ngAfterContentChecked()
|
Performs actions after content has been checked.
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Performs actions after the view has been initialized.
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Performs actions before the component is destroyed.
Returns :
void
|
document |
Type : Document
|
Reference to the Document object for interacting with the DOM. |
Public documentImported |
Type : Document
|
Decorators :
@Inject(DOCUMENT)
|
Reference to the Document object for interacting with the DOM.
|
Optional elementToScroll |
Type : HTMLElement | null |
|
Element that have the scroll listener |
Public getWindow |
Type : GetWindow
|
Reference to the GetWindow service for safely accessing the window object.
|
onScroll |
Default value : () => {...}
|
Handles the scroll event and triggers loading more items if applicable. |
Optional scrollElement |
Type : ElementRef
|
Decorators :
@ViewChild('scroll', {static: true})
|
Reference to the scroll element. |
tresholdScroll |
Type : number
|
Default value : 25
|
Threshold for scrolling. |
import { DOCUMENT } from '@angular/common'
import { AfterContentChecked, AfterViewInit, Component, ElementRef, EventEmitter, Inject, Input, OnDestroy, Output, ViewChild } from '@angular/core'
import { GetWindow } from '../../helpers/window.helper'
/**
* Represents the SqInfinityComponent, a component for infinite scrolling.
*
* @implements {AfterViewInit}
* @implements {AfterContentChecked}
* @implements {OnDestroy}
*
* @example
* <sq-infinity-scroll [length]="totalItems" [hasMore]="hasMoreData" [loading]="isLoading" (scrolledEmitter)="loadMoreItems()">
* <!-- Content Here -->
* </sq-infinity-scroll>
*/
@Component({
selector: 'sq-infinity-scroll',
templateUrl: './sq-infinity-scroll.component.html',
styleUrls: ['./sq-infinity-scroll.component.scss']
})
export class SqInfinityComponent implements AfterViewInit, AfterContentChecked, OnDestroy {
/**
* Reference to the scroll element.
*/
@ViewChild('scroll', { static: true }) scrollElement?: ElementRef
/**
* The total number of items in the list.
*/
@Input() length = 0
/**
* The message to display when reaching the end of the list.
*/
@Input() endMessage?: string
/**
* Indicates whether there are more items to load.
*/
@Input() hasMore?: boolean | string = true
/**
* Indicates whether data is currently being loaded.
*/
@Input() loading?: boolean
/**
* The color of the loader.
*/
@Input() loaderColor?: string
/**
* The ID of the element to scroll (if using a custom scrolling element).
*/
@Input() elementToScrollId?: string
/**
* Event emitter for when the user scrolls to trigger loading more items.
*/
@Output() scrolledEmitter: EventEmitter<void> = new EventEmitter()
/**
* Element that have the scroll listener
*/
elementToScroll?: HTMLElement | null | Window & typeof globalThis
/**
* Reference to the Document object for interacting with the DOM.
*/
document: Document
/**
* Threshold for scrolling.
*/
tresholdScroll = 25
/**
* Creates an instance of SqInfinityComponent.
* @constructor
* @param {Document} documentImported Reference to the Document object for interacting with the DOM.
* @param {GetWindow} getWindow Reference to the GetWindow service for safely accessing the window object.
*/
constructor(@Inject(DOCUMENT) public documentImported: Document, public getWindow: GetWindow) {
this.document = this.documentImported || document
}
/**
* Performs actions after the view has been initialized.
*/
ngAfterViewInit(): void {
const { elementToScrollId } = this
if (elementToScrollId) {
this.elementToScroll = this.document.getElementById(elementToScrollId)
}
if (!elementToScrollId || !this.elementToScroll) {
this.elementToScroll = this.getWindow.window()
}
this.elementToScroll?.addEventListener('scroll', this.onScroll, false)
}
/**
* Performs actions after content has been checked.
*/
ngAfterContentChecked(): void {
if (this.elementToScrollId && this.elementToScroll && this.elementToScroll instanceof HTMLElement && typeof this.elementToScroll.getAttribute === 'undefined') {
const element = this.document.getElementById(this.elementToScrollId)
if (element) {
this.elementToScroll.removeEventListener('scroll', this.onScroll, false)
element.addEventListener('scroll', this.onScroll, false)
this.elementToScroll = element
}
}
}
/**
* Performs actions before the component is destroyed.
*/
ngOnDestroy(): void {
this.elementToScroll?.removeEventListener('scroll', this.onScroll, false)
}
/**
* Handles the scroll event and triggers loading more items if applicable.
*/
onScroll = () => {
if (!this.loading && this.length > 0 && this.hasMore) {
if (this.elementToScrollId && this.elementToScroll instanceof HTMLElement) {
const allScroll = this.elementToScroll?.scrollTop + this.elementToScroll?.clientHeight
if (allScroll + this.tresholdScroll >= this.elementToScroll?.scrollHeight) {
this.elementToScroll?.removeEventListener('scroll', this.onScroll, false)
this.scrolledEmitter.emit()
this.elementToScroll?.addEventListener('scroll', this.onScroll, false)
}
} else if (this.elementToScroll instanceof Window) {
const elementHeight = this.elementToScroll?.innerHeight
const elementY = this.elementToScroll?.scrollY
if (elementHeight + elementY + this.tresholdScroll >= this.scrollElement?.nativeElement.offsetHeight + this.scrollElement?.nativeElement.offsetTop) {
this.elementToScroll?.removeEventListener('scroll', this.onScroll, false)
this.scrolledEmitter.emit()
this.elementToScroll?.addEventListener('scroll', this.onScroll, false)
}
}
}
}
}
<div #scroll class="scroll">
<ng-content></ng-content>
<div *ngIf="loading" class="infinity-loader">
<sq-loader color="{{ loaderColor }}"></sq-loader>
</div>
<div class="wrapper-message" *ngIf="!hasMore && endMessage">
<p>
{{ endMessage || '' }}
</p>
</div>
</div>
./sq-infinity-scroll.component.scss
.scroll {
width: 100%;
height: auto;
position: relative;
.wrapper-message {
p {
text-align: center;
font-size: 0.86rem;
margin: 1.1rem auto;
}
}
}
.infinity-loader {
position: absolute;
bottom: 0;
right: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: var(--white-html);
}