Skip to content

Commit 948711f

Browse files
authored
Merge branch '9.0.x' into nrobakova/fix-issue-7528-90
2 parents 6ddcb4e + 3ba4f28 commit 948711f

File tree

10 files changed

+225
-11
lines changed

10 files changed

+225
-11
lines changed

projects/igniteui-angular/src/lib/grids/grid-base.directive.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4298,9 +4298,9 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
42984298
/**
42994299
* @hidden
43004300
*/
4301-
protected getPagingHeight(): number {
4301+
protected getPagingFooterHeight(): number {
43024302
let pagingHeight = 0;
4303-
if (this.paging && this.footer) {
4303+
if (this.footer) {
43044304
pagingHeight = this.footer.nativeElement.firstElementChild ?
43054305
this.footer.nativeElement.offsetHeight : 0;
43064306
}
@@ -4331,7 +4331,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
43314331
this.theadRow.nativeElement.offsetHeight;
43324332
const footerHeight = this.summariesHeight || this.tfoot.nativeElement.offsetHeight - this.tfoot.nativeElement.clientHeight;
43334333
const toolbarHeight = this.getToolbarHeight();
4334-
const pagingHeight = this.getPagingHeight();
4334+
const pagingHeight = this.getPagingFooterHeight();
43354335
const groupAreaHeight = this.getGroupAreaHeight();
43364336
const renderedHeight = toolbarHeight + actualTheadRow +
43374337
footerHeight + pagingHeight + groupAreaHeight +
@@ -5067,15 +5067,17 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
50675067
let record = {};
50685068
const selectedData = [];
50695069
const activeEl = this.selectionService.activeElement;
5070-
5071-
const selectionMap = Array.from(this.selectionService.selection)
5072-
.filter((tuple) => tuple[0] < source.length);
5070+
const totalItems = (this as any).totalItemCount ?? 0;
5071+
const isRemote = totalItems && totalItems > this.dataView.length;
5072+
const selectionMap = isRemote ? Array.from(this.selectionService.selection) :
5073+
Array.from(this.selectionService.selection).filter((tuple) => tuple[0] < source.length);
50735074

50745075
if (this.cellSelection === GridSelectionMode.single && activeEl) {
50755076
selectionMap.push([activeEl.row, new Set<number>().add(activeEl.column)]);
50765077
}
50775078

5078-
for (const [row, set] of selectionMap) {
5079+
for (let [row, set] of selectionMap) {
5080+
row = isRemote ? row - this.virtualizationState.startIndex : row;
50795081
if (!source[row] || source[row].detailsData !== undefined) {
50805082
continue;
50815083
}

projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,10 @@ describe('IgxGrid Component Tests #grid', () => {
17031703
const footerContent = footer.textContent.trim();
17041704

17051705
expect(footerContent).toEqual('Custom content');
1706+
const grid = fix.componentInstance.grid;
1707+
1708+
const expectedHeight = parseInt(grid.height, 10) - grid.theadRow.nativeElement.offsetHeight - grid.scrollWidth - 100;
1709+
expect(expectedHeight - grid.calcHeight).toBeLessThanOrEqual(1);
17061710
});
17071711
});
17081712

@@ -2090,15 +2094,19 @@ export class IgxGridColumnPercentageWidthComponent extends IgxGridDefaultRenderi
20902094
@Component({
20912095
template:
20922096
`<div>
2093-
<igx-grid #grid [data]="data" [displayDensity]="'compact'" [autoGenerate]="true"
2094-
[paging]="true" [perPage]="5">
2097+
<igx-grid #grid [data]="data" height='300px' [displayDensity]="'compact'" [autoGenerate]="true"
2098+
>
20952099
<igx-grid-footer>
2096-
Custom content
2100+
<div style='height:100px;'>
2101+
Custom content
2102+
</div>
20972103
</igx-grid-footer>
20982104
</igx-grid>
20992105
</div>`
21002106
})
21012107
export class IgxGridWithCustomFooterComponent extends IgxGridTestComponent {
2108+
public data = SampleTestData.foodProductData();
2109+
@ViewChild(IgxGridComponent, { static: true }) public grid: IgxGridComponent;
21022110
}
21032111
@Component({
21042112
template:

src/app/app.component.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ export class AppComponent implements OnInit {
232232
icon: 'view_column',
233233
name: 'Grid Remote Virtualization'
234234
},
235+
{
236+
link: '/gridScrollVirtualization',
237+
icon: 'view_column',
238+
name: 'Grid Remote Virtualization with Scroll'
239+
},
235240
{
236241
link: '/gridRowEdit',
237242
icon: 'view_column',

src/app/app.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ import { GridExternalFilteringComponent } from './grid-external-filtering/grid-e
115115
import { AboutComponent } from './grid-state/about.component';
116116
import { GridSaveStateComponent } from './grid-state/grid-state.component';
117117
import { GridMasterDetailSampleComponent } from './grid-master-detail/grid-master-detail.sample';
118+
import { GridVirtualizationScrollSampleComponent } from './grid-remote-virtualization-with-scroll/grid-remote-virtualization-scroll.sample';
118119

119120
const components = [
120121
AppComponent,
@@ -220,7 +221,8 @@ const components = [
220221
GridFilteringComponent,
221222
GridExternalFilteringComponent,
222223
GridSaveStateComponent,
223-
AboutComponent
224+
AboutComponent,
225+
GridVirtualizationScrollSampleComponent
224226
];
225227

226228
@NgModule({

src/app/app.routing.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import { GridAutoSizeSampleComponent } from './grid-auto-size/grid-auto-size.sam
6868
import { GridSaveStateComponent } from './grid-state/grid-state.component';
6969
import { AboutComponent } from './grid-state/about.component';
7070
import { GridMasterDetailSampleComponent } from './grid-master-detail/grid-master-detail.sample';
71+
import { GridVirtualizationScrollSampleComponent } from './grid-remote-virtualization-with-scroll/grid-remote-virtualization-scroll.sample';
7172

7273
const appRoutes = [
7374
{
@@ -330,6 +331,10 @@ const appRoutes = [
330331
path: 'gridAbout',
331332
component: AboutComponent
332333
},
334+
{
335+
path: 'gridScrollVirtualization',
336+
component: GridVirtualizationScrollSampleComponent
337+
}
333338
];
334339

335340
export const routing = RouterModule.forRoot(appRoutes);

src/app/grid-column-moving/grid-column-moving.sample.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
[hasSummary]="false"
3737
[dataType]="c.type">
3838
</igx-column>
39+
<igx-grid-footer>
40+
<div style='height:200px;'>
41+
Test
42+
</div>
43+
</igx-grid-footer>
3944
</igx-grid>
4045
Drag mode: {{ grid1.selectionService.dragMode }}
4146
<div class="sample-buttons">
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div class="sample-wrapper dark-grid">
2+
<igx-grid #grid1 [data]="remoteData | async" [height]="'500px'" [width]="'100%'" [autoGenerate]='true' (onDataPreLoad)="handlePreLoad()" [clipboardOptions]="clipboardOptions"
3+
(onSortingDone)="processData(true)">
4+
</igx-grid>
5+
</div>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Component, ViewChild, ChangeDetectorRef, OnInit, AfterViewInit } from '@angular/core';
2+
import { IgxGridComponent } from 'igniteui-angular';
3+
import { debounceTime } from 'rxjs/operators';
4+
import { RemoteVirtService } from '../shared/remote.service - Copy';
5+
6+
@Component({
7+
selector: 'app-grid-remote-virtualization-scroll',
8+
templateUrl: 'grid-remote-virtualization-scroll.sample.html',
9+
providers: [RemoteVirtService]
10+
})
11+
12+
export class GridVirtualizationScrollSampleComponent implements OnInit, AfterViewInit {
13+
14+
public remoteData: any;
15+
public prevRequest: any;
16+
public columns: any;
17+
public loading = true;
18+
19+
@ViewChild('grid1', { static: true })
20+
public grid: IgxGridComponent;
21+
22+
public clipboardOptions = {
23+
enabled: true,
24+
copyHeaders: false,
25+
copyFormatters: true,
26+
separator: '\t'
27+
};
28+
constructor(private remoteService: RemoteVirtService, public cdr: ChangeDetectorRef) { }
29+
30+
public ngOnInit(): void {
31+
this.remoteData = this.remoteService.data;
32+
}
33+
34+
public ngAfterViewInit() {
35+
this.grid.isLoading = true;
36+
37+
this.remoteService.getData(this.grid.virtualizationState, this.grid.sortingExpressions[0], true, (data) => {
38+
this.grid.totalItemCount = data['@odata.count'];
39+
this.grid.isLoading = false;
40+
});
41+
42+
this.grid.onDataPreLoad.pipe(debounceTime(500)).subscribe(() => {
43+
this.processData(false);
44+
});
45+
}
46+
47+
public handlePreLoad() {
48+
if (this.remoteService.hasItemsInCache(this.grid.virtualizationState)) {
49+
this.processData(false);
50+
}
51+
}
52+
53+
public processData(reset) {
54+
if (this.prevRequest) {
55+
this.prevRequest.unsubscribe();
56+
}
57+
this.prevRequest = this.remoteService.getData(this.grid.virtualizationState,
58+
this.grid.sortingExpressions[0], reset, () => {
59+
this.cdr.detectChanges();
60+
});
61+
}
62+
}

src/app/routing.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import { GridExternalFilteringComponent } from './grid-external-filtering/grid-e
9292
import { GridSaveStateComponent } from './grid-state/grid-state.component';
9393
import { AboutComponent } from './grid-state/about.component';
9494
import { GridMasterDetailSampleComponent } from './grid-master-detail/grid-master-detail.sample';
95+
import { GridVirtualizationScrollSampleComponent } from './grid-remote-virtualization-with-scroll/grid-remote-virtualization-scroll.sample';
9596

9697
const appRoutes = [
9798
{
@@ -396,6 +397,10 @@ const appRoutes = [
396397
path: 'gridRowEdit',
397398
component: GridRowEditSampleComponent
398399
},
400+
{
401+
path: 'gridScrollVirtualization',
402+
component: GridVirtualizationScrollSampleComponent
403+
},
399404
{
400405
path: 'treeGrid',
401406
component: TreeGridSampleComponent
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
2+
import { HttpClient } from '@angular/common/http';
3+
import { Injectable } from '@angular/core';
4+
import { SortingDirection } from 'igniteui-angular';
5+
import { BehaviorSubject, Observable } from 'rxjs';
6+
7+
const DATA_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Products';
8+
const EMPTY_STRING = '';
9+
export enum SortOrder {
10+
ASC = 'asc',
11+
DESC = 'desc',
12+
NONE = ''
13+
}
14+
@Injectable()
15+
export class RemoteVirtService {
16+
17+
public data: Observable<any[]>;
18+
private _data: BehaviorSubject<any[]>;
19+
private _cachedData: any[];
20+
21+
constructor(private _http: HttpClient) {
22+
this._data = new BehaviorSubject([]);
23+
this.data = this._data.asObservable();
24+
}
25+
26+
public hasItemsInCache(virtualizationArgs?) {
27+
const startIndex = virtualizationArgs.startIndex;
28+
const endIndex = virtualizationArgs.chunkSize + startIndex;
29+
let areAllItemsInCache = true;
30+
for (let i = startIndex; i < endIndex; i++) {
31+
if (this._cachedData[i] === null) {
32+
areAllItemsInCache = false;
33+
break;
34+
}
35+
}
36+
return areAllItemsInCache;
37+
}
38+
39+
public getData(virtualizationArgs?, sortingArgs?: any, resetData?: boolean, cb?: (any) => void): any {
40+
const startIndex = virtualizationArgs.startIndex;
41+
const endIndex = virtualizationArgs.chunkSize + startIndex;
42+
43+
if (resetData) {
44+
this._http.get(this._buildDataUrl(virtualizationArgs, sortingArgs)).subscribe((data: any) => {
45+
this._cachedData = new Array<any>(data['@odata.count']).fill(null);
46+
this._updateData(data, startIndex);
47+
if (cb) {
48+
cb(data);
49+
}
50+
});
51+
52+
return;
53+
}
54+
55+
if (!this.hasItemsInCache(virtualizationArgs)) {
56+
this._http.get(this._buildDataUrl(virtualizationArgs, sortingArgs)).subscribe((data: any) => {
57+
this._updateData(data, startIndex);
58+
if (cb) {
59+
cb(data);
60+
}
61+
});
62+
} else {
63+
const data = this._cachedData.slice(startIndex, endIndex);
64+
this._data.next(data);
65+
if (cb) {
66+
cb(data);
67+
}
68+
}
69+
}
70+
71+
private _updateData(data: any, startIndex: number) {
72+
this._data.next(data.value);
73+
for (let i = 0; i < data.value.length; i++) {
74+
this._cachedData[i + startIndex] = data.value[i];
75+
}
76+
}
77+
78+
private _buildDataUrl(virtualizationArgs: any, sortingArgs: any): string {
79+
let baseQueryString = `${DATA_URL}?$count=true`;
80+
let scrollingQuery = EMPTY_STRING;
81+
let orderQuery = EMPTY_STRING;
82+
let query = EMPTY_STRING;
83+
84+
if (sortingArgs) {
85+
let sortingDirection: string;
86+
switch (sortingArgs.dir) {
87+
case SortingDirection.Asc:
88+
sortingDirection = SortOrder.ASC;
89+
break;
90+
case SortingDirection.Desc:
91+
sortingDirection = SortOrder.DESC;
92+
break;
93+
default:
94+
sortingDirection = SortOrder.NONE;
95+
}
96+
97+
orderQuery = `$orderby=${sortingArgs.fieldName} ${sortingDirection}`;
98+
}
99+
100+
if (virtualizationArgs) {
101+
let requiredChunkSize: number;
102+
const skip = virtualizationArgs.startIndex;
103+
requiredChunkSize = virtualizationArgs.chunkSize === 0 ? 11 : virtualizationArgs.chunkSize;
104+
const top = requiredChunkSize;
105+
scrollingQuery = `$skip=${skip}&$top=${top}`;
106+
}
107+
108+
query += (orderQuery !== EMPTY_STRING) ? `&${orderQuery}` : EMPTY_STRING;
109+
query += (scrollingQuery !== EMPTY_STRING) ? `&${scrollingQuery}` : EMPTY_STRING;
110+
111+
baseQueryString += query;
112+
113+
return baseQueryString;
114+
}
115+
}

0 commit comments

Comments
 (0)