Skip to content

Commit 21883b0

Browse files
committed
feat(grid): adding ghost rows to flat grid #6640
1 parent 5ab9919 commit 21883b0

10 files changed

+117
-98
lines changed

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

+7
Original file line numberDiff line numberDiff line change
@@ -6319,6 +6319,13 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
63196319
}
63206320
}
63216321

6322+
/**
6323+
* @hidden @internal
6324+
*/
6325+
public isGhostRecord(record: any): boolean {
6326+
return record.ghostRecord !== undefined;
6327+
}
6328+
63226329
/**
63236330
* Opens the advanced filtering dialog.
63246331
*/

projects/igniteui-angular/src/lib/grids/grid/grid.component.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
<ng-container *ngIf='data
115115
| gridTransaction:id:pipeTrigger
116116
| visibleColumns:hasVisibleColumns
117-
| rowPinning:id:true:pipeTrigger
117+
| gridRowPinning:pipeTrigger
118118
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger:true
119119
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger:true
120120
| gridDetails:hasDetails:expansionStates:pipeTrigger as pinnedData'>
@@ -134,12 +134,12 @@
134134
<ng-template igxGridFor let-rowData [igxGridForOf]="data
135135
| gridTransaction:id:pipeTrigger
136136
| visibleColumns:hasVisibleColumns
137-
| rowPinning:id:false:pipeTrigger
138137
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
139138
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
140139
| gridGroupBy:groupingExpressions:groupingExpansionState:groupsExpanded:id:groupsRecords:pipeTrigger
141140
| gridPaging:page:perPage:id:pipeTrigger
142141
| gridSummary:hasSummarizedColumns:summaryCalculationMode:summaryPosition:id:pipeTrigger:summaryPipeTrigger
142+
| gridGhostRecords:pipeTrigger
143143
| gridDetails:hasDetails:expansionStates:pipeTrigger"
144144
let-rowIndex="index" [igxForScrollOrientation]="'vertical'" [igxForScrollContainer]='verticalScroll'
145145
[igxForContainerSize]='calcHeight'

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -853,9 +853,11 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
853853
};
854854
}
855855
}
856+
const isGhost = this.isGhostRecord(rowData);
856857
return {
857-
$implicit: rowData,
858+
$implicit: isGhost ? rowData.recordRef : rowData,
858859
index: rowIndex,
860+
disabled: isGhost,
859861
templateID: this.isGroupByRecord(rowData) ? 'groupRow' : this.isSummaryRow(rowData) ? 'summaryRow' : 'dataRow'
860862
};
861863
}

projects/igniteui-angular/src/lib/grids/grid/grid.module.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
IgxGridGroupingPipe,
1515
IgxGridSortingPipe,
1616
IgxGridFilteringPipe,
17-
IgxGridRowPinningPipe
17+
IgxGridRowPinningPipe,
18+
IgxGridGhostRecordsPipe
1819
} from './grid.pipes';
1920
import { IgxGridGroupByRowComponent } from './groupby-row.component';
2021
import { IgxGridRowComponent } from './grid-row.component';
@@ -45,6 +46,7 @@ import { IgxGridExpandableCellComponent } from './expandable-cell.component';
4546
IgxGridRowPinningPipe,
4647
IgxGridSummaryPipe,
4748
IgxGridDetailsPipe,
49+
IgxGridGhostRecordsPipe,
4850
IgxGridExpandableCellComponent
4951
],
5052
exports: [
@@ -66,6 +68,7 @@ import { IgxGridExpandableCellComponent } from './expandable-cell.component';
6668
IgxGridRowPinningPipe,
6769
IgxGridSummaryPipe,
6870
IgxGridDetailsPipe,
71+
IgxGridGhostRecordsPipe,
6972
IgxGridCommonModule
7073
],
7174
imports: [

projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts

+28-12
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,9 @@ export class IgxGridPagingPipe implements PipeTransform {
103103
if (!this.gridAPI.grid.paging) {
104104
return collection;
105105
}
106-
const _perPage = perPage - this.gridAPI.grid.pinnedRecordsCount;
107106
const state = {
108107
index: page,
109-
recordsPerPage: _perPage
108+
recordsPerPage: perPage
110109
};
111110
DataUtil.correctPagingState(state, collection.data.length);
112111

@@ -157,27 +156,44 @@ export class IgxGridFilteringPipe implements PipeTransform {
157156
* @hidden
158157
*/
159158
@Pipe({
160-
name: 'rowPinning',
159+
name: 'gridRowPinning',
161160
pure: true
162161
})
163162
export class IgxGridRowPinningPipe implements PipeTransform {
164163

165164
constructor(private gridAPI: GridBaseAPIService<IgxGridBaseDirective & GridType>) {}
166165

167-
public transform(collection: any[] , id: string, isPinned = false, pipeTrigger: number) {
166+
public transform(collection: any[]) {
168167
const grid = this.gridAPI.grid;
169168

170169
if (!grid.hasPinnedRecords) {
171-
return isPinned ? [] : collection;
170+
return [];
172171
}
173172

174-
const result = collection.filter((value, index) => {
175-
return isPinned ? grid.isRecordPinned(value) : !grid.isRecordPinned(value);
176-
});
177-
if (isPinned) {
178-
// pinned records should be ordered as they were pinned.
179-
result.sort((rec1, rec2) => grid.pinRecordIndex(rec1) - grid.pinRecordIndex(rec2));
173+
// pinned records should be ordered as they were pinned.
174+
return collection
175+
.filter(value => grid.isRecordPinned(value))
176+
.sort((rec1, rec2) => grid.pinRecordIndex(rec1) - grid.pinRecordIndex(rec2));
177+
}
178+
}
179+
180+
@Pipe({
181+
name: 'gridGhostRecords',
182+
pure: true
183+
})
184+
export class IgxGridGhostRecordsPipe implements PipeTransform {
185+
186+
constructor(private gridAPI: GridBaseAPIService<IgxGridBaseDirective & GridType>) {}
187+
188+
public transform(collection: any[]) {
189+
const grid = this.gridAPI.grid;
190+
191+
if (!grid.hasPinnedRecords) {
192+
return collection;
180193
}
181-
return result;
194+
195+
return collection.map((rec) => {
196+
return grid.isRecordPinned(rec) ? { recordRef: rec, ghostRecord: true} : rec;
197+
});
182198
}
183199
}

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

+69-47
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DebugElement, ViewChild, Component } from '@angular/core';
1+
import { ViewChild, Component } from '@angular/core';
22
import { TestBed, async, fakeAsync, tick } from '@angular/core/testing';
33
import { By } from '@angular/platform-browser';
44
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@@ -360,7 +360,7 @@ describe('Row Pinning #grid', () => {
360360
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
361361
expect(pinRowContainer.length).toBe(1);
362362

363-
let expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
363+
let expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
364364
expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1);
365365

366366
grid.filter('ID', 'B', IgxStringFilteringOperand.instance().condition('startsWith'), false);
@@ -370,7 +370,7 @@ describe('Row Pinning #grid', () => {
370370
expect(pinRowContainer.length).toBe(0);
371371

372372
expect(grid.pinnedRowHeight).toBe(0);
373-
expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
373+
expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
374374
expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1);
375375
});
376376

@@ -397,47 +397,6 @@ describe('Row Pinning #grid', () => {
397397
expect(gridFilterData[1].ID).toBe('BERGS');
398398
});
399399

400-
it('should page through unpinned collection with modified pageSize = pageSize - pinnedRows.lenght.', () => {
401-
// pin 2nd row
402-
grid.paging = true;
403-
grid.perPage = 5;
404-
fix.detectChanges();
405-
const paginator = fix.debugElement.query(By.directive(IgxPaginatorComponent));
406-
expect(paginator.componentInstance.totalPages).toEqual(6);
407-
408-
grid.getRowByIndex(1).pin();
409-
fix.detectChanges();
410-
411-
expect(grid.pinnedRows.length).toBe(1);
412-
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
413-
expect(pinRowContainer.length).toBe(1);
414-
expect(grid.dataView.length).toBe(4);
415-
expect(paginator.componentInstance.totalPages).toEqual(6);
416-
417-
grid.getRowByIndex(3).pin();
418-
fix.detectChanges();
419-
420-
expect(grid.pinnedRows.length).toBe(2);
421-
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
422-
expect(pinRowContainer.length).toBe(1);
423-
expect(grid.dataView.length).toBe(3);
424-
expect(paginator.componentInstance.totalPages).toEqual(5);
425-
426-
// unpin
427-
grid.getRowByIndex(0).unpin();
428-
fix.detectChanges();
429-
430-
grid.getRowByIndex(0).unpin();
431-
fix.detectChanges();
432-
433-
expect(grid.pinnedRows.length).toBe(0);
434-
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
435-
expect(pinRowContainer.length).toBe(0);
436-
437-
expect(grid.dataView.length).toBe(5);
438-
expect(paginator.componentInstance.totalPages).toEqual(6);
439-
});
440-
441400
it('should apply sorting to both pinned and unpinned rows.', () => {
442401
grid.getRowByIndex(1).pin();
443402
grid.getRowByIndex(5).pin();
@@ -458,6 +417,7 @@ describe('Row Pinning #grid', () => {
458417
expect(grid.getRowByIndex(2).rowID).toBe(fix.componentInstance.data[lastIndex]);
459418
});
460419
});
420+
461421
describe('Row pinning with Master Detail View', () => {
462422
beforeEach(fakeAsync(() => {
463423
fix = TestBed.createComponent(GridRowPinningWithMDVComponent);
@@ -550,6 +510,62 @@ describe('Row Pinning #grid', () => {
550510
});
551511
});
552512

513+
describe('Paging', () => {
514+
let paginator: IgxPaginatorComponent;
515+
516+
beforeEach(fakeAsync(() => {
517+
fix = TestBed.createComponent(GridRowPinningComponent);
518+
fix.componentInstance.createSimpleData(12);
519+
grid = fix.componentInstance.instance;
520+
grid.paging = true;
521+
grid.perPage = 5;
522+
523+
fix.detectChanges();
524+
tick();
525+
526+
paginator = fix.debugElement.query(By.directive(IgxPaginatorComponent)).componentInstance;
527+
}));
528+
529+
it('should correctly apply paging state for grid and paginator when there are pinned rows.', () => {
530+
// pin the first row
531+
grid.getRowByIndex(0).pin();
532+
fix.detectChanges();
533+
534+
expect(grid.rowList.length).toEqual(6);
535+
expect(grid.perPage).toEqual(5);
536+
expect(paginator.perPage).toEqual(5);
537+
expect(paginator.totalRecords).toEqual(12);
538+
expect(paginator.totalPages).toEqual(3);
539+
540+
// pin the second row
541+
grid.getRowByIndex(2).pin();
542+
fix.detectChanges();
543+
544+
expect(grid.rowList.length).toEqual(7);
545+
expect(grid.perPage).toEqual(5);
546+
expect(paginator.perPage).toEqual(5);
547+
expect(paginator.totalRecords).toEqual(12);
548+
expect(paginator.totalPages).toEqual(3);
549+
});
550+
551+
it('should have the correct records shown for pages with pinned rows', () => {
552+
grid.getRowByIndex(0).pin();
553+
grid.getRowByIndex(1).pin();
554+
fix.detectChanges();
555+
556+
let rows = grid.rowList.toArray();
557+
558+
[1, 2, 1, 2, 3, 4, 5].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x));
559+
560+
grid.paginate(2);
561+
fix.detectChanges();
562+
563+
rows = grid.rowList.toArray();
564+
565+
[1, 2, 11, 12].forEach((x, index) => expect(rows[index].cells.first.value).toEqual(x));
566+
});
567+
});
568+
553569
describe(' Editing ', () => {
554570
beforeEach(fakeAsync(() => {
555571
fix = TestBed.createComponent(GridRowPinningWithTransactionsComponent);
@@ -628,6 +644,7 @@ describe('Row Pinning #grid', () => {
628644
});
629645

630646
});
647+
631648
describe('Row pinning with MRL', () => {
632649
beforeEach(fakeAsync(() => {
633650
fix = TestBed.createComponent(GridRowPinningWithMRLComponent);
@@ -714,6 +731,7 @@ describe('Row Pinning #grid', () => {
714731
verifyDOMMatchesLayoutSettings(gridUnpinnedRow, fix.componentInstance.colGroups);
715732
});
716733
});
734+
717735
describe(' Hiding', () => {
718736
beforeEach(fakeAsync(() => {
719737
fix = TestBed.createComponent(GridRowPinningComponent);
@@ -773,11 +791,15 @@ describe('Row Pinning #grid', () => {
773791
`
774792
})
775793
export class GridRowPinningComponent {
776-
public data = SampleTestData.contactInfoDataFull();
794+
public data: any[] = SampleTestData.contactInfoDataFull();
777795
public pinningConfig: IPinningConfig = { columns: ColumnPinningPosition.Start, rows: RowPinningPosition.Top };
778796

779797
@ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true })
780798
public instance: IgxGridComponent;
799+
800+
public createSimpleData(count: number) {
801+
this.data = Array(count).fill({}).map((x, idx) => x = { 'idx': idx + 1 });
802+
}
781803
}
782804

783805
@Component({
@@ -823,7 +845,7 @@ export class GridRowPinningWithMRLComponent extends GridRowPinningComponent {
823845
</ng-template>
824846
</igx-grid>`
825847
})
826-
export class GridRowPinningWithMDVComponent extends GridRowPinningComponent {}
848+
export class GridRowPinningWithMDVComponent extends GridRowPinningComponent { }
827849

828850

829851
@Component({
@@ -839,4 +861,4 @@ export class GridRowPinningWithMDVComponent extends GridRowPinningComponent {}
839861
`,
840862
providers: [{ provide: IgxGridTransaction, useClass: IgxTransactionService }]
841863
})
842-
export class GridRowPinningWithTransactionsComponent extends GridRowPinningComponent {}
864+
export class GridRowPinningWithTransactionsComponent extends GridRowPinningComponent { }

projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
<ng-container *ngIf="data
9696
| gridTransaction:id:pipeTrigger
9797
| visibleColumns:hasVisibleColumns
98-
| gridHierarchicalRowPinning:true:pipeTrigger
98+
| gridRowPinning:pipeTrigger
9999
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger:true
100100
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger as pinnedData">
101101
<div #pinContainer *ngIf='pinnedData.length > 0' class='igx-grid__tr--pinned'
@@ -114,9 +114,9 @@
114114
| gridTransaction:id:pipeTrigger
115115
| visibleColumns:hasVisibleColumns
116116
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
117-
| gridHierarchicalRowPinning:false:pipeTrigger
118117
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
119118
| gridHierarchicalPaging:page:perPage:id:pipeTrigger
119+
| gridGhostRecords:pipeTrigger
120120
| gridHierarchical:expansionStates:id:primaryKey:childLayoutKeys:pipeTrigger"
121121
[igxForScrollOrientation]="'vertical'" [igxForScrollContainer]='verticalScroll'
122122
[igxForContainerSize]='calcHeight' [igxForItemSize]="renderedRowHeight" [igxForTrackBy]='trackChanges'

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

-4
Original file line numberDiff line numberDiff line change
@@ -520,10 +520,6 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti
520520
return record.childGridsData !== undefined;
521521
}
522522

523-
public isGhostRecord(record: any): boolean {
524-
return record.ghostRecord !== undefined;
525-
}
526-
527523
/**
528524
* @hidden
529525
*/

projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';
22
import { IgxGridModule } from '../grid/grid.module';
33
import { IgxHierarchicalGridComponent } from './hierarchical-grid.component';
44
import { IgxHierarchicalRowComponent } from './hierarchical-row.component';
5-
import { IgxGridHierarchicalPipe, IgxGridHierarchicalPagingPipe, IgxGridHierarchicalRowPinning } from './hierarchical-grid.pipes';
5+
import { IgxGridHierarchicalPipe, IgxGridHierarchicalPagingPipe } from './hierarchical-grid.pipes';
66
import { IgxRowIslandComponent } from './row-island.component';
77
import { IgxChildGridRowComponent } from './child-grid-row.component';
88
import { IgxHierarchicalGridCellComponent } from './hierarchical-cell.component';
@@ -21,8 +21,7 @@ import { IgxHierarchicalGridBaseDirective } from './hierarchical-grid-base.direc
2121
IgxChildGridRowComponent,
2222
IgxHierarchicalGridCellComponent,
2323
IgxGridHierarchicalPipe,
24-
IgxGridHierarchicalPagingPipe,
25-
IgxGridHierarchicalRowPinning
24+
IgxGridHierarchicalPagingPipe
2625
],
2726
exports: [
2827
IgxGridModule,

0 commit comments

Comments
 (0)