1 | import { EventEmitter, Component, ChangeDetectionStrategy, ViewEncapsulation, ElementRef, Input, ContentChild, ContentChildren, ViewChild, Output, NgModule } from '@angular/core';
|
2 | import { CommonModule } from '@angular/common';
|
3 | import { Header, Footer, PrimeTemplate, SharedModule } from 'primeng/api';
|
4 | import { CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
|
5 |
|
6 | class VirtualScroller {
|
7 | constructor(el) {
|
8 | this.el = el;
|
9 | this.trackBy = (index, item) => item;
|
10 | this.onLazyLoad = new EventEmitter();
|
11 | this._totalRecords = 0;
|
12 | this.page = 0;
|
13 | this._first = 0;
|
14 | this.loadedPages = [];
|
15 | }
|
16 | get totalRecords() {
|
17 | return this._totalRecords;
|
18 | }
|
19 | set totalRecords(val) {
|
20 | this._totalRecords = val;
|
21 | console.log("totalRecords is deprecated, provide a value with the length of virtual items instead.");
|
22 | }
|
23 | get first() {
|
24 | return this._first;
|
25 | }
|
26 | set first(val) {
|
27 | this._first = val;
|
28 | console.log("first property is deprecated, use scrollToIndex function to scroll a specific item.");
|
29 | }
|
30 | get cache() {
|
31 | return this._cache;
|
32 | }
|
33 | set cache(val) {
|
34 | this._cache = val;
|
35 | console.log("cache is deprecated as it is always on.");
|
36 | }
|
37 | ngAfterContentInit() {
|
38 | this.templates.forEach((item) => {
|
39 | switch (item.getType()) {
|
40 | case 'item':
|
41 | this.itemTemplate = item.template;
|
42 | break;
|
43 | case 'loadingItem':
|
44 | this.loadingItemTemplate = item.template;
|
45 | break;
|
46 | case 'header':
|
47 | this.headerTemplate = item.template;
|
48 | break;
|
49 | case 'footer':
|
50 | this.footerTemplate = item.template;
|
51 | break;
|
52 | default:
|
53 | this.itemTemplate = item.template;
|
54 | break;
|
55 | }
|
56 | });
|
57 | }
|
58 | onScrollIndexChange(index) {
|
59 | if (this.lazy) {
|
60 | let pageRange = this.createPageRange(Math.floor(index / this.rows));
|
61 | pageRange.forEach(page => this.loadPage(page));
|
62 | }
|
63 | }
|
64 | createPageRange(page) {
|
65 | let range = [];
|
66 | if (page !== 0) {
|
67 | range.push(page - 1);
|
68 | }
|
69 | range.push(page);
|
70 | if (page !== (Math.ceil(this.value.length / this.rows) - 1)) {
|
71 | range.push(page + 1);
|
72 | }
|
73 | return range;
|
74 | }
|
75 | loadPage(page) {
|
76 | if (!this.loadedPages.includes(page)) {
|
77 | this.onLazyLoad.emit({ first: this.rows * page, rows: this.rows });
|
78 | this.loadedPages.push(page);
|
79 | }
|
80 | }
|
81 | getBlockableElement() {
|
82 | return this.el.nativeElement.children[0];
|
83 | }
|
84 |
|
85 | scrollTo(index, mode) {
|
86 | this.scrollToIndex(index, mode);
|
87 | }
|
88 | scrollToIndex(index, mode) {
|
89 | if (this.viewport) {
|
90 | this.viewport.scrollToIndex(index, mode);
|
91 | }
|
92 | }
|
93 | clearCache() {
|
94 | this.loadedPages = [];
|
95 | }
|
96 | ngOnChanges(simpleChange) {
|
97 | if (simpleChange.value) {
|
98 | if (!this.lazy) {
|
99 | this.clearCache();
|
100 | }
|
101 | }
|
102 | }
|
103 | }
|
104 | VirtualScroller.decorators = [
|
105 | { type: Component, args: [{
|
106 | selector: 'p-virtualScroller',
|
107 | template: `
|
108 | <div [ngClass]="'p-virtualscroller p-component'" [ngStyle]="style" [class]="styleClass">
|
109 | <div class="p-virtualscroller-header" *ngIf="header || headerTemplate">
|
110 | <ng-content select="p-header"></ng-content>
|
111 | <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
|
112 | </div>
|
113 | <div #content class="p-virtualscroller-content">
|
114 | <div class="p-virtualscroller-list">
|
115 | <cdk-virtual-scroll-viewport #viewport [ngStyle]="{'height': scrollHeight}" [itemSize]="itemSize" [minBufferPx]="minBufferPx" [maxBufferPx]="maxBufferPx" (scrolledIndexChange)="onScrollIndexChange($event)">
|
116 | <ng-container *cdkVirtualFor="let item of value; trackBy: trackBy; let i = index; let c = count; let f = first; let l = last; let e = even; let o = odd;">
|
117 | <div [ngStyle]="{'height': itemSize + 'px'}" class="p-virtualscroller-item">
|
118 | <ng-container *ngTemplateOutlet="item ? itemTemplate : loadingItemTemplate; context: {$implicit: item, index: i, count: c, first: f, last: l, even: e, odd: o}"></ng-container>
|
119 | </div>
|
120 | </ng-container>
|
121 | </cdk-virtual-scroll-viewport>
|
122 | </div>
|
123 | </div>
|
124 | <div class="p-virtualscroller-footer" *ngIf="footer || footerTemplate">
|
125 | <ng-content select="p-footer"></ng-content>
|
126 | <ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
|
127 | </div>
|
128 | </div>
|
129 | `,
|
130 | changeDetection: ChangeDetectionStrategy.Default,
|
131 | encapsulation: ViewEncapsulation.None
|
132 | },] }
|
133 | ];
|
134 | VirtualScroller.ctorParameters = () => [
|
135 | { type: ElementRef }
|
136 | ];
|
137 | VirtualScroller.propDecorators = {
|
138 | value: [{ type: Input }],
|
139 | itemSize: [{ type: Input }],
|
140 | style: [{ type: Input }],
|
141 | styleClass: [{ type: Input }],
|
142 | scrollHeight: [{ type: Input }],
|
143 | lazy: [{ type: Input }],
|
144 | rows: [{ type: Input }],
|
145 | minBufferPx: [{ type: Input }],
|
146 | maxBufferPx: [{ type: Input }],
|
147 | trackBy: [{ type: Input }],
|
148 | header: [{ type: ContentChild, args: [Header,] }],
|
149 | footer: [{ type: ContentChild, args: [Footer,] }],
|
150 | templates: [{ type: ContentChildren, args: [PrimeTemplate,] }],
|
151 | viewport: [{ type: ViewChild, args: [CdkVirtualScrollViewport,] }],
|
152 | onLazyLoad: [{ type: Output }],
|
153 | totalRecords: [{ type: Input }],
|
154 | first: [{ type: Input }],
|
155 | cache: [{ type: Input }]
|
156 | };
|
157 | class VirtualScrollerModule {
|
158 | }
|
159 | VirtualScrollerModule.decorators = [
|
160 | { type: NgModule, args: [{
|
161 | imports: [CommonModule, ScrollingModule],
|
162 | exports: [VirtualScroller, SharedModule, ScrollingModule],
|
163 | declarations: [VirtualScroller]
|
164 | },] }
|
165 | ];
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 | export { VirtualScroller, VirtualScrollerModule };
|
172 |
|