Amend VirtualScroller
This commit is contained in:
17
src/app/component/grid-items/grid-items.component.html
Normal file
17
src/app/component/grid-items/grid-items.component.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<div #container class="card flex justify-center">
|
||||||
|
hi there!
|
||||||
|
<p-virtualscroller
|
||||||
|
[items]="items"
|
||||||
|
[itemSize]="[50, 100]"
|
||||||
|
orientation="both"
|
||||||
|
styleClass="border border-surface"
|
||||||
|
[autoSize]="true"
|
||||||
|
[style]="{ width: '400px', height: '200px' }"
|
||||||
|
>
|
||||||
|
<ng-template pTemplate="item" let-item let-options="options">
|
||||||
|
<div class="flex items-center p-2" [ngClass]="{ 'bg-surface-100 dark:bg-surface-700': options.odd }" style="height: 50px;">
|
||||||
|
<div *ngFor="let el of item" style="width: 100px">{{ el }}</div>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</p-virtualscroller>
|
||||||
|
</div>
|
||||||
23
src/app/component/grid-items/grid-items.component.spec.ts
Normal file
23
src/app/component/grid-items/grid-items.component.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { GridItemsComponent } from './grid-items.component';
|
||||||
|
|
||||||
|
describe('GridItemsComponent', () => {
|
||||||
|
let component: GridItemsComponent;
|
||||||
|
let fixture: ComponentFixture<GridItemsComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [GridItemsComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(GridItemsComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
33
src/app/component/grid-items/grid-items.component.ts
Normal file
33
src/app/component/grid-items/grid-items.component.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
|
||||||
|
import {Scroller, ScrollerModule} from 'primeng/scroller';
|
||||||
|
import {NgClass, NgForOf, NgStyle} from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-grid-items',
|
||||||
|
imports: [
|
||||||
|
ScrollerModule,
|
||||||
|
NgClass,
|
||||||
|
NgForOf,
|
||||||
|
NgStyle
|
||||||
|
],
|
||||||
|
styles: [
|
||||||
|
`:host ::ng-deep {
|
||||||
|
.p-scroller-viewport {
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
],
|
||||||
|
templateUrl: './grid-items.component.html',
|
||||||
|
styleUrl: './grid-items.component.css'
|
||||||
|
})
|
||||||
|
export class GridItemsComponent implements OnInit {
|
||||||
|
@ViewChild('container') containerRef!: ElementRef<HTMLElement>;
|
||||||
|
|
||||||
|
private readonly FONT_SIZE_PX = 14;
|
||||||
|
items!: string[][];
|
||||||
|
widthTest: string = '300px';
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.items = Array.from({ length: 1000 }).map((_, i) => Array.from({ length: 1000 }).map((_j, j) => `Item #${i}_${j}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +1,21 @@
|
|||||||
<div #container class="h-full w-screen">
|
<div #container class="h-full w-screen">
|
||||||
@if (initialized) {
|
@if (this.initialized) {
|
||||||
<p-virtualscroller
|
<p-virtualscroller
|
||||||
[items]="cards"
|
[items]="cardRows"
|
||||||
[itemSize]="itemSize"
|
[itemSize]="[itemWidthInPx,itemHeightInPx]"
|
||||||
[lazy]="true"
|
[lazy]="true"
|
||||||
[loading]="lazyLoading"
|
[loading]="lazyLoading"
|
||||||
[appendOnly]="true"
|
[appendOnly]="true"
|
||||||
[step]="pageSize"
|
|
||||||
[numToleratedItems]="numberOfToleratedItems"
|
|
||||||
(onLazyLoad)="onLazyLoad($event)"
|
(onLazyLoad)="onLazyLoad($event)"
|
||||||
scrollHeight="600px"
|
orientation="both"
|
||||||
scrollWidth="600px"
|
[style]="{ width: '100vw', height: '100%' }"
|
||||||
>
|
>
|
||||||
<ng-template
|
<ng-template #item let-item let-options="options">
|
||||||
[appVirtualScroll]="cards"
|
<div class="flex justify-around">
|
||||||
pTemplate="content"
|
<p-card
|
||||||
let-options="options"
|
*ngFor="let card of item"
|
||||||
|
styleClass="w-[24rem] h-[36rem] m-2 overflow-hidden"
|
||||||
>
|
>
|
||||||
<div class="flex-none flex-wrap justify-around">
|
|
||||||
@for (card of options.items; track card.id) {
|
|
||||||
<p-card styleClass="w-[24rem] h-[36rem] m-2 overflow-hidden">
|
|
||||||
<ng-template pTemplate="header">
|
<ng-template pTemplate="header">
|
||||||
<div
|
<div
|
||||||
class="relative duration-200 w-[23rem] rounded-lg ease-in-out h-64 z-10 overflow-hidden hover:h-[34rem] hover:translate-y-2 m-2 after:absolute after:inset-0 after:shadow-[inset_0_-10px_30px_15px_rgba(0,0,0,0.85)] after:content-[''] hover:inset-0"
|
class="relative duration-200 w-[23rem] rounded-lg ease-in-out h-64 z-10 overflow-hidden hover:h-[34rem] hover:translate-y-2 m-2 after:absolute after:inset-0 after:shadow-[inset_0_-10px_30px_15px_rgba(0,0,0,0.85)] after:content-[''] hover:inset-0"
|
||||||
@@ -50,11 +46,10 @@
|
|||||||
quas!
|
quas!
|
||||||
</p>
|
</p>
|
||||||
</p-card>
|
</p-card>
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</p-virtualscroller>
|
</p-virtualscroller>
|
||||||
} @else {
|
} @else {
|
||||||
hold on im pogging rn
|
hold on im poggin
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
// noinspection DuplicatedCode
|
// noinspection DuplicatedCode
|
||||||
|
|
||||||
import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
|
import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
|
||||||
import {Scroller, ScrollerLazyLoadEvent} from 'primeng/scroller';
|
import {Scroller, ScrollerLazyLoadEvent} from 'primeng/scroller';
|
||||||
import {Card as CardModel, CardService, PageDeck} from '../../openapi';
|
import {Card as CardModel, CardService} from '../../openapi';
|
||||||
import {BehaviorSubject, catchError, debounceTime, of, Subject, switchMap} from 'rxjs';
|
import {catchError, debounceTime, of, Subject, switchMap} from 'rxjs';
|
||||||
import {Button} from 'primeng/button';
|
import {Button} from 'primeng/button';
|
||||||
import {Card} from 'primeng/card';
|
import {Card} from 'primeng/card';
|
||||||
import {PrimeTemplate} from 'primeng/api';
|
import {PrimeTemplate} from 'primeng/api';
|
||||||
import {VirtualScrollDirective} from '../../directives/virtual-scroll.directive';
|
import {NgForOf} from '@angular/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-cards',
|
selector: 'app-cards',
|
||||||
imports: [
|
imports: [
|
||||||
|
Scroller,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
PrimeTemplate,
|
PrimeTemplate,
|
||||||
Scroller,
|
NgForOf
|
||||||
VirtualScrollDirective
|
|
||||||
],
|
],
|
||||||
templateUrl: './cards.component.html',
|
templateUrl: './cards.component.html',
|
||||||
styleUrl: './cards.component.css'
|
styleUrl: './cards.component.css'
|
||||||
@@ -29,21 +29,21 @@ export class CardsComponent implements AfterViewInit {
|
|||||||
|
|
||||||
private readonly FONT_SIZE_PX = 14;
|
private readonly FONT_SIZE_PX = 14;
|
||||||
|
|
||||||
private pageSubject = new BehaviorSubject<number>(0);
|
private pageSubject = new Subject<number>();
|
||||||
private resizeObserver!: ResizeObserver;
|
private resizeObserver!: ResizeObserver;
|
||||||
|
|
||||||
pageSize: number = 5;
|
|
||||||
page: number = 0;
|
page: number = 0;
|
||||||
// noinspection PointlessArithmeticExpressionJS Card height + ( margin top/bottom) (rem)
|
pageSize: number = 5;
|
||||||
rowHeight: number = 36 + (0.5 * 2);
|
itemHeight: number = 36 + (0.5 * 2);
|
||||||
itemWidth: number = 24; // Card width (rem)
|
itemWidth: number = 24;
|
||||||
cards: CardModel[] = [];
|
itemHeightInPx: number = this.itemHeight * this.FONT_SIZE_PX;
|
||||||
lazyLoading: boolean = false;
|
itemWidthInPx: number = this.itemWidth * this.FONT_SIZE_PX;
|
||||||
|
cardRows: CardModel[][] = [];
|
||||||
|
lazyLoading: boolean = true;
|
||||||
|
initialized: boolean = false;
|
||||||
itemsPerRow!: number;
|
itemsPerRow!: number;
|
||||||
rowsInPage!: number;
|
rowsInPage!: number;
|
||||||
itemSize: number = this.rowHeight;
|
lastResponseSize?: number;
|
||||||
numberOfToleratedItems: number = 5;
|
|
||||||
initialized: boolean = false;
|
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
this.setupResizeObserver();
|
this.setupResizeObserver();
|
||||||
@@ -65,54 +65,38 @@ export class CardsComponent implements AfterViewInit {
|
|||||||
)
|
)
|
||||||
.subscribe(cards => {
|
.subscribe(cards => {
|
||||||
this.lazyLoading = false;
|
this.lazyLoading = false;
|
||||||
|
|
||||||
|
if (!this.lastResponseSize) {
|
||||||
|
this.lastResponseSize = cards.length;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.initialized) {
|
if (!this.initialized) {
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cards = [
|
this.cardRows[this.page] = cards
|
||||||
...this.cards,
|
console.log(cards.length);
|
||||||
...cards
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupResizeObserver(): void {
|
private setupResizeObserver(): void {
|
||||||
this.resizeObserver = new ResizeObserver(entries => {
|
this.resizeObserver = new ResizeObserver(entries => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
this.calculateRowsInPage(entry.contentRect.height);
|
this.rowsInPage = Math.ceil(entry.contentRect.height / this.itemHeightInPx);
|
||||||
this.calculateItemsPerRow(entry.contentRect.width);
|
this.itemsPerRow = Math.floor(entry.contentRect.width / this.itemWidthInPx);
|
||||||
|
this.pageSize = this.itemsPerRow;
|
||||||
const itemsInViewPort = this.itemsPerRow * this.rowsInPage;
|
|
||||||
this.pageSize = itemsInViewPort;
|
|
||||||
this.numberOfToleratedItems = itemsInViewPort;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.resizeObserver.observe(this.containerRef.nativeElement);
|
this.resizeObserver.observe(this.containerRef.nativeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private calculateItemsPerRow(containerWidth: number): void {
|
|
||||||
const newItemsPerRow = Math.floor(containerWidth / (this.itemWidth * this.FONT_SIZE_PX)) || 1;
|
|
||||||
|
|
||||||
if (newItemsPerRow !== this.itemsPerRow) {
|
|
||||||
this.itemsPerRow = newItemsPerRow;
|
|
||||||
}
|
|
||||||
this.updateVirtualScrollerSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
private calculateRowsInPage(containerHeight: number) {
|
|
||||||
this.rowsInPage = Math.ceil(containerHeight / (this.rowHeight * this.FONT_SIZE_PX));
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateVirtualScrollerSettings(): void {
|
|
||||||
this.itemSize = (this.rowHeight * this.FONT_SIZE_PX) / this.itemsPerRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
onLazyLoad(event: ScrollerLazyLoadEvent) {
|
onLazyLoad(event: ScrollerLazyLoadEvent) {
|
||||||
if (!event || event.last % this.pageSize !== 0) {
|
console.log(`kinda pogging rn cuz ${JSON.stringify(event)}`)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.pageSubject.next(++this.page);
|
this.pageSubject.next(++this.page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected readonly JSON = JSON;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user