Skip to content

Commit e54b6f1

Browse files
authored
Merge pull request #6907 from IgniteUI/mkirova/row-pinning-editing
Row Pinning + Editing
2 parents 5b82df1 + 422a6b2 commit e54b6f1

File tree

9 files changed

+176
-44
lines changed

9 files changed

+176
-44
lines changed

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

+36-17
Original file line numberDiff line numberDiff line change
@@ -2479,15 +2479,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
24792479
*/
24802480
protected _columnPinning = false;
24812481

2482-
2483-
/**
2484-
* @hidden
2485-
*/
2486-
public get pinnedRecords() {
2487-
return this._pinnedRecords;
2488-
}
2489-
2490-
protected _pinnedRecords = [];
2482+
protected _pinnedRecordIDs = [];
24912483

24922484
/**
24932485
* @hidden
@@ -2652,6 +2644,32 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
26522644
});
26532645
}
26542646

2647+
/**
2648+
* @hidden
2649+
* @internal
2650+
*/
2651+
public isRecordPinned(rec) {
2652+
const id = this.primaryKey ? rec[this.primaryKey] : rec;
2653+
return this._pinnedRecordIDs.indexOf(id) !== -1;
2654+
}
2655+
2656+
/**
2657+
* @hidden
2658+
* @internal
2659+
*/
2660+
public pinRecordIndex(rec) {
2661+
const id = this.primaryKey ? rec[this.primaryKey] : rec;
2662+
return this._pinnedRecordIDs.indexOf(id);
2663+
}
2664+
2665+
/**
2666+
* @hidden
2667+
* @internal
2668+
*/
2669+
public get hasPinnedRecords() {
2670+
return this._pinnedRecordIDs.length > 0;
2671+
}
2672+
26552673
private keydownHandler = (event) => {
26562674
const key = event.key.toLowerCase();
26572675
if ((isNavigationKey(key) && event.keyCode !== 32) || key === 'tab' || key === 'pagedown' || key === 'pageup') {
@@ -4066,8 +4084,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
40664084
* @param index The index at which to insert the row in the pinned collection.
40674085
*/
40684086
public pinRow(rowID: any, index?: number): boolean {
4069-
const rec = this.gridAPI.get_rec_by_id(rowID);
4070-
if (!rec || this.pinnedRecords.indexOf(rec) !== -1 || this.data.indexOf(rec) === -1) {
4087+
if (this._pinnedRecordIDs.indexOf(rowID) !== -1) {
40714088
return false;
40724089
}
40734090
const row = this.gridAPI.get_row_by_key(rowID);
@@ -4080,7 +4097,9 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
40804097
};
40814098
this.onRowPinning.emit(eventArgs);
40824099

4083-
this.pinnedRecords.splice(eventArgs.insertAtIndex || this.pinnedRecords.length, 0, rec);
4100+
this.endEdit(true);
4101+
4102+
this._pinnedRecordIDs.splice(eventArgs.insertAtIndex || this._pinnedRecordIDs.length, 0, rowID);
40844103
this._pipeTrigger++;
40854104
if (this.gridAPI.grid) {
40864105
this.notifyChanges(true);
@@ -4098,9 +4117,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
40984117
* @param rowID The row id - primaryKey value or the data record instance.
40994118
*/
41004119
public unpinRow(rowID: any) {
4101-
const rec = this.gridAPI.get_rec_by_id(rowID);
4102-
const index = this.pinnedRecords.indexOf(rec);
4103-
if (index === -1 || !rec) {
4120+
const index = this._pinnedRecordIDs.indexOf(rowID);
4121+
if (index === -1) {
41044122
return false;
41054123
}
41064124
const row = this.gridAPI.get_row_by_key(rowID);
@@ -4110,7 +4128,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
41104128
row: row
41114129
};
41124130
this.onRowPinning.emit(eventArgs);
4113-
this.pinnedRecords.splice(index, 1);
4131+
this.endEdit(true);
4132+
this._pinnedRecordIDs.splice(index, 1);
41144133
this._pipeTrigger++;
41154134
if (this.gridAPI.grid) {
41164135
this.cdr.detectChanges();
@@ -4121,7 +4140,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
41214140

41224141
get pinnedRowHeight() {
41234142
const containerHeight = this.pinContainer ? this.pinContainer.nativeElement.offsetHeight : 0;
4124-
return this.pinnedRecords.length > 0 ? containerHeight : 0;
4143+
return this._pinnedRecordIDs.length > 0 ? containerHeight : 0;
41254144
}
41264145

41274146
get totalHeight() {

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

+6-4
Original file line numberDiff line numberDiff line change
@@ -109,23 +109,25 @@
109109
[igxColumnMovingDrop]="headerContainer" [attr.droppable]="true" id="left"
110110
class="igx-grid__scroll-on-drag-pinned" [style.left.px]="pinnedWidth"></span>
111111
<ng-template #pinnedRecordsTemplate>
112-
<ng-container *ngFor="let rowData of pinnedRecords
112+
<ng-container *ngFor="let rowData of data
113+
| gridTransaction:id:pipeTrigger
113114
| visibleColumns:hasVisibleColumns
115+
| rowPinning:id:true:pipeTrigger
114116
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
115117
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
116118
| gridDetails:hasDetails:expansionStates:pipeTrigger; let rowIndex = index">
117119
<ng-container *ngTemplateOutlet="getRowTemplate(rowData); context: getContext(rowData, rowIndex, true)">
118120
</ng-container>
119121
</ng-container>
120122
</ng-template>
121-
<div #pinContainer *ngIf='pinnedRecords.length > 0 && isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-top'>
123+
<div #pinContainer *ngIf='hasPinnedRecords && isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-top'>
122124
<ng-container *ngTemplateOutlet="pinnedRecordsTemplate">
123125
</ng-container>
124126
</div>
125127
<ng-template igxGridFor let-rowData [igxGridForOf]="data
126128
| gridTransaction:id:pipeTrigger
127129
| visibleColumns:hasVisibleColumns
128-
| rowPinning:id:pipeTrigger
130+
| rowPinning:id:false:pipeTrigger
129131
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
130132
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
131133
| gridGroupBy:groupingExpressions:groupingExpansionState:groupsExpanded:id:groupsRecords:pipeTrigger
@@ -146,7 +148,7 @@
146148
(onBeforeViewDetach)='viewDetachHandler($event)'>
147149
</ng-template>
148150
</ng-template>
149-
<div #pinContainer *ngIf='pinnedRecords.length > 0 && !isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-bottom' [style.bottom.px]='pinnedBottom'>
151+
<div #pinContainer *ngIf='hasPinnedRecords && !isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-bottom' [style.bottom.px]='pinnedBottom'>
150152
<ng-container *ngTemplateOutlet="pinnedRecordsTemplate">
151153
</ng-container>
152154
</div>

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
830830
if (pinned && !this.isRowPinningToTop) {
831831
rowIndex = rowIndex + this.dataView.length;
832832
}
833-
rowIndex = !pinned && this.isRowPinningToTop ? rowIndex + this.pinnedRecords.length : rowIndex;
833+
rowIndex = !pinned && this.isRowPinningToTop ? rowIndex + this._pinnedRecordIDs.length : rowIndex;
834834
if (this.isDetailRecord(rowData)) {
835835
const cachedData = this.childDetailTemplates.get(rowData.detailsData);
836836
const rowID = this.primaryKey ? rowData.detailsData[this.primaryKey] : this.data.indexOf(rowData.detailsData);

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

+9-5
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,20 @@ export class IgxGridRowPinningPipe implements PipeTransform {
164164

165165
constructor(private gridAPI: GridBaseAPIService<IgxGridBaseDirective & GridType>) {}
166166

167-
public transform(collection: any[] , id: string, pipeTrigger: number) {
167+
public transform(collection: any[] , id: string, isPinned = false, pipeTrigger: number) {
168168
const grid = this.gridAPI.grid;
169-
const pinnedRows = grid.pinnedRecords;
170-
if (pinnedRows.length === 0) {
171-
return collection;
169+
170+
if (!grid.hasPinnedRecords) {
171+
return isPinned ? [] : collection;
172172
}
173173

174174
const result = collection.filter((value, index) => {
175-
return pinnedRows.indexOf(value) === -1;
175+
return isPinned ? grid.isRecordPinned(value) : !grid.isRecordPinned(value);
176176
});
177+
if (isPinned) {
178+
// pinned records should be ordered as they were pinned.
179+
result.sort((rec1, rec2) => grid.pinRecordIndex(rec1) - grid.pinRecordIndex(rec2));
180+
}
177181
return result;
178182
}
179183
}

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

+110-9
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,21 @@ import { configureTestSuite } from '../../test-utils/configure-suite';
88
import { ColumnPinningPosition, RowPinningPosition } from '../common/enums';
99
import { IPinningConfig } from '../common/grid.interface';
1010
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
11+
import { IgxGridTransaction } from '../tree-grid';
12+
import { IgxTransactionService } from '../../services';
1113

1214
describe('Row Pinning #grid', () => {
1315
const FIXED_ROW_CONTAINER = '.igx-grid__tr--pinned ';
16+
const CELL_CSS_CLASS = '.igx-grid__td';
1417
configureTestSuite();
1518
let fix;
1619
let grid: IgxGridComponent;
1720

1821
beforeAll(async(() => {
1922
TestBed.configureTestingModule({
2023
declarations: [
21-
GridRowPinningComponent
24+
GridRowPinningComponent,
25+
GridRowPinningWithTransactionsComponent
2226
],
2327
imports: [
2428
NoopAnimationsModule,
@@ -42,7 +46,7 @@ describe('Row Pinning #grid', () => {
4246
grid.pinRow(fix.componentInstance.data[1]);
4347
fix.detectChanges();
4448

45-
expect(grid.pinnedRecords.length).toBe(1);
49+
expect(grid.pinnedRows.length).toBe(1);
4650
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
4751
expect(pinRowContainer.length).toBe(1);
4852
expect(pinRowContainer[0].children.length).toBe(1);
@@ -78,7 +82,7 @@ describe('Row Pinning #grid', () => {
7882
grid.pinRow(fix.componentInstance.data[1]);
7983
fix.detectChanges();
8084

81-
expect(grid.pinnedRecords.length).toBe(1);
85+
expect(grid.pinnedRows.length).toBe(1);
8286
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
8387
expect(pinRowContainer.length).toBe(1);
8488
expect(pinRowContainer[0].children.length).toBe(1);
@@ -138,7 +142,7 @@ describe('Row Pinning #grid', () => {
138142
grid.pinRow(fix.componentInstance.data[1]);
139143
fix.detectChanges();
140144

141-
expect(grid.pinnedRecords.length).toBe(1);
145+
expect(grid.pinnedRows.length).toBe(1);
142146
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
143147
expect(pinRowContainer.length).toBe(1);
144148
expect(pinRowContainer[0].children.length).toBe(1);
@@ -153,7 +157,7 @@ describe('Row Pinning #grid', () => {
153157
grid.unpinRow(fix.componentInstance.data[1]);
154158
fix.detectChanges();
155159

156-
expect(grid.pinnedRecords.length).toBe(0);
160+
expect(grid.pinnedRows.length).toBe(0);
157161
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
158162
expect(pinRowContainer.length).toBe(0);
159163

@@ -167,7 +171,7 @@ describe('Row Pinning #grid', () => {
167171
row.pin();
168172
fix.detectChanges();
169173

170-
expect(grid.pinnedRecords.length).toBe(1);
174+
expect(grid.pinnedRows.length).toBe(1);
171175
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
172176
expect(pinRowContainer.length).toBe(1);
173177
expect(pinRowContainer[0].children.length).toBe(1);
@@ -181,7 +185,7 @@ describe('Row Pinning #grid', () => {
181185
row.unpin();
182186
fix.detectChanges();
183187

184-
expect(grid.pinnedRecords.length).toBe(0);
188+
expect(grid.pinnedRows.length).toBe(0);
185189
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
186190
expect(pinRowContainer.length).toBe(0);
187191

@@ -195,7 +199,7 @@ describe('Row Pinning #grid', () => {
195199
row.pinned = true;
196200
fix.detectChanges();
197201

198-
expect(grid.pinnedRecords.length).toBe(1);
202+
expect(grid.pinnedRows.length).toBe(1);
199203
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
200204
expect(pinRowContainer.length).toBe(1);
201205
expect(pinRowContainer[0].children.length).toBe(1);
@@ -209,14 +213,93 @@ describe('Row Pinning #grid', () => {
209213
row.pinned = false;
210214
fix.detectChanges();
211215

212-
expect(grid.pinnedRecords.length).toBe(0);
216+
expect(grid.pinnedRows.length).toBe(0);
213217
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
214218
expect(pinRowContainer.length).toBe(0);
215219

216220
expect(grid.getRowByIndex(0).rowID).toBe(fix.componentInstance.data[0]);
217221
expect(grid.getRowByIndex(1).rowID).toBe(fix.componentInstance.data[1]);
218222
});
219223
});
224+
225+
describe(' Editing ', () => {
226+
beforeEach(fakeAsync(() => {
227+
fix = TestBed.createComponent(GridRowPinningWithTransactionsComponent);
228+
fix.detectChanges();
229+
grid = fix.componentInstance.instance;
230+
tick();
231+
fix.detectChanges();
232+
}));
233+
234+
it('should allow pinning edited row.', () => {
235+
grid.updateCell('New value', 'ANTON', 'CompanyName');
236+
fix.detectChanges();
237+
grid.pinRow('ANTON');
238+
fix.detectChanges();
239+
240+
expect(grid.pinnedRows.length).toBe(1);
241+
const pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
242+
expect(pinRowContainer.length).toBe(1);
243+
expect(pinRowContainer[0].children.length).toBe(1);
244+
expect(pinRowContainer[0].children[0].context.rowID).toBe('ANTON');
245+
expect(pinRowContainer[0].children[0].context.rowData.CompanyName).toBe('New value');
246+
});
247+
248+
it('should allow pinning deleted row.', () => {
249+
grid.deleteRow('ALFKI');
250+
fix.detectChanges();
251+
grid.pinRow('ALFKI');
252+
fix.detectChanges();
253+
254+
expect(grid.pinnedRows.length).toBe(1);
255+
const pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
256+
expect(pinRowContainer.length).toBe(1);
257+
expect(pinRowContainer[0].children.length).toBe(1);
258+
expect(pinRowContainer[0].children[0].context.rowID).toBe('ALFKI');
259+
});
260+
261+
it('should allow pinning added row.', () => {
262+
263+
grid.addRow({ 'ID': 'Test', 'CompanyName': 'Test'});
264+
fix.detectChanges();
265+
266+
grid.pinRow('Test');
267+
fix.detectChanges();
268+
expect(grid.pinnedRows.length).toBe(1);
269+
const pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
270+
expect(pinRowContainer.length).toBe(1);
271+
expect(pinRowContainer[0].children.length).toBe(1);
272+
expect(pinRowContainer[0].children[0].context.rowID).toBe('Test');
273+
});
274+
275+
it('should stop editing when edited row is pinned/unpinned.', () => {
276+
grid.getColumnByName('CompanyName').editable = true;
277+
fix.detectChanges();
278+
let cell = grid.getCellByColumn(0, 'CompanyName');
279+
let cellDomNumber = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS))[1];
280+
cellDomNumber.triggerEventHandler('dblclick', {});
281+
fix.detectChanges();
282+
283+
expect(cell.editMode).toBeTruthy();
284+
285+
grid.pinRow(cell.row.rowID);
286+
fix.detectChanges();
287+
288+
cell = grid.getCellByColumn(0, 'CompanyName');
289+
expect(cell.editMode).toBeFalsy();
290+
291+
cellDomNumber = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS))[1];
292+
cellDomNumber.triggerEventHandler('dblclick', {});
293+
fix.detectChanges();
294+
295+
expect(cell.editMode).toBeTruthy();
296+
grid.unpinRow(cell.row.rowID);
297+
fix.detectChanges();
298+
cell = grid.getCellByColumn(0, 'CompanyName');
299+
expect(cell.editMode).toBeFalsy();
300+
});
301+
302+
});
220303
});
221304

222305
@Component({
@@ -237,3 +320,21 @@ export class GridRowPinningComponent {
237320
@ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true })
238321
public instance: IgxGridComponent;
239322
}
323+
324+
325+
@Component({
326+
template: `
327+
<igx-grid
328+
[pinning]='pinningConfig'
329+
primaryKey='ID'
330+
[width]='"800px"'
331+
[height]='"500px"'
332+
[data]="data"
333+
[autoGenerate]="true">
334+
</igx-grid>
335+
`,
336+
providers: [{ provide: IgxGridTransaction, useClass: IgxTransactionService }]
337+
})
338+
export class GridRowPinningWithTransactionsComponent extends GridRowPinningComponent {
339+
public data = SampleTestData.contactInfoDataFull();
340+
}

projects/igniteui-angular/src/lib/grids/row.directive.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class IgxRowDirective<T extends IgxGridBaseDirective & GridType> implemen
6565
* ```
6666
*/
6767
public get pinned(): boolean {
68-
return this.grid.pinnedRecords.indexOf(this.rowData) !== -1;
68+
return this.grid.isRecordPinned(this.rowData);
6969
}
7070
/**
7171
* Sets whether the row is pinned.

src/app/grid-column-pinning/grid-column-pinning.sample.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ export class GridColumnPinningSampleComponent implements OnInit {
103103

104104
togglePinRow(index) {
105105
const rec = this.data[index];
106-
this.grid1.pinnedRecords.indexOf(rec) === -1 ?
107-
this.grid1.pinRow(this.data[index]) :
108-
this.grid1.unpinRow(this.data[index])
106+
this.grid1.isRecordPinned(rec) ?
107+
this.grid1.pinRow(rec) :
108+
this.grid1.unpinRow(rec)
109109
}
110110

111111
}

0 commit comments

Comments
 (0)