Skip to content

Row Pinning + Editing #6907

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Mar 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 36 additions & 17 deletions projects/igniteui-angular/src/lib/grids/grid-base.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2479,15 +2479,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
*/
protected _columnPinning = false;


/**
* @hidden
*/
public get pinnedRecords() {
return this._pinnedRecords;
}

protected _pinnedRecords = [];
protected _pinnedRecordIDs = [];

/**
* @hidden
Expand Down Expand Up @@ -2652,6 +2644,32 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
});
}

/**
* @hidden
* @internal
*/
public isRecordPinned(rec) {
const id = this.primaryKey ? rec[this.primaryKey] : rec;
return this._pinnedRecordIDs.indexOf(id) !== -1;
}

/**
* @hidden
* @internal
*/
public pinRecordIndex(rec) {
const id = this.primaryKey ? rec[this.primaryKey] : rec;
return this._pinnedRecordIDs.indexOf(id);
}

/**
* @hidden
* @internal
*/
public get hasPinnedRecords() {
return this._pinnedRecordIDs.length > 0;
}

private keydownHandler = (event) => {
const key = event.key.toLowerCase();
if ((isNavigationKey(key) && event.keyCode !== 32) || key === 'tab' || key === 'pagedown' || key === 'pageup') {
Expand Down Expand Up @@ -4066,8 +4084,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
* @param index The index at which to insert the row in the pinned collection.
*/
public pinRow(rowID: any, index?: number): boolean {
const rec = this.gridAPI.get_rec_by_id(rowID);
if (!rec || this.pinnedRecords.indexOf(rec) !== -1 || this.data.indexOf(rec) === -1) {
if (this._pinnedRecordIDs.indexOf(rowID) !== -1) {
return false;
}
const row = this.gridAPI.get_row_by_key(rowID);
Expand All @@ -4080,7 +4097,9 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
};
this.onRowPinning.emit(eventArgs);

this.pinnedRecords.splice(eventArgs.insertAtIndex || this.pinnedRecords.length, 0, rec);
this.endEdit(true);

this._pinnedRecordIDs.splice(eventArgs.insertAtIndex || this._pinnedRecordIDs.length, 0, rowID);
this._pipeTrigger++;
if (this.gridAPI.grid) {
this.notifyChanges(true);
Expand All @@ -4098,9 +4117,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
* @param rowID The row id - primaryKey value or the data record instance.
*/
public unpinRow(rowID: any) {
const rec = this.gridAPI.get_rec_by_id(rowID);
const index = this.pinnedRecords.indexOf(rec);
if (index === -1 || !rec) {
const index = this._pinnedRecordIDs.indexOf(rowID);
if (index === -1) {
return false;
}
const row = this.gridAPI.get_row_by_key(rowID);
Expand All @@ -4110,7 +4128,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
row: row
};
this.onRowPinning.emit(eventArgs);
this.pinnedRecords.splice(index, 1);
this.endEdit(true);
this._pinnedRecordIDs.splice(index, 1);
this._pipeTrigger++;
if (this.gridAPI.grid) {
this.cdr.detectChanges();
Expand All @@ -4121,7 +4140,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements

get pinnedRowHeight() {
const containerHeight = this.pinContainer ? this.pinContainer.nativeElement.offsetHeight : 0;
return this.pinnedRecords.length > 0 ? containerHeight : 0;
return this._pinnedRecordIDs.length > 0 ? containerHeight : 0;
}

get totalHeight() {
Expand Down
10 changes: 6 additions & 4 deletions projects/igniteui-angular/src/lib/grids/grid/grid.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,23 +109,25 @@
[igxColumnMovingDrop]="headerContainer" [attr.droppable]="true" id="left"
class="igx-grid__scroll-on-drag-pinned" [style.left.px]="pinnedWidth"></span>
<ng-template #pinnedRecordsTemplate>
<ng-container *ngFor="let rowData of pinnedRecords
<ng-container *ngFor="let rowData of data
| gridTransaction:id:pipeTrigger
| visibleColumns:hasVisibleColumns
| rowPinning:id:true:pipeTrigger
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
| gridDetails:hasDetails:expansionStates:pipeTrigger; let rowIndex = index">
<ng-container *ngTemplateOutlet="getRowTemplate(rowData); context: getContext(rowData, rowIndex, true)">
</ng-container>
</ng-container>
</ng-template>
<div #pinContainer *ngIf='pinnedRecords.length > 0 && isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-top'>
<div #pinContainer *ngIf='hasPinnedRecords && isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-top'>
<ng-container *ngTemplateOutlet="pinnedRecordsTemplate">
</ng-container>
</div>
<ng-template igxGridFor let-rowData [igxGridForOf]="data
| gridTransaction:id:pipeTrigger
| visibleColumns:hasVisibleColumns
| rowPinning:id:pipeTrigger
| rowPinning:id:false:pipeTrigger
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
| gridGroupBy:groupingExpressions:groupingExpansionState:groupsExpanded:id:groupsRecords:pipeTrigger
Expand All @@ -146,7 +148,7 @@
(onBeforeViewDetach)='viewDetachHandler($event)'>
</ng-template>
</ng-template>
<div #pinContainer *ngIf='pinnedRecords.length > 0 && !isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-bottom' [style.bottom.px]='pinnedBottom'>
<div #pinContainer *ngIf='hasPinnedRecords && !isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-bottom' [style.bottom.px]='pinnedBottom'>
<ng-container *ngTemplateOutlet="pinnedRecordsTemplate">
</ng-container>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
if (pinned && !this.isRowPinningToTop) {
rowIndex = rowIndex + this.dataView.length;
}
rowIndex = !pinned && this.isRowPinningToTop ? rowIndex + this.pinnedRecords.length : rowIndex;
rowIndex = !pinned && this.isRowPinningToTop ? rowIndex + this._pinnedRecordIDs.length : rowIndex;
if (this.isDetailRecord(rowData)) {
const cachedData = this.childDetailTemplates.get(rowData.detailsData);
const rowID = this.primaryKey ? rowData.detailsData[this.primaryKey] : this.data.indexOf(rowData.detailsData);
Expand Down
14 changes: 9 additions & 5 deletions projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,16 +164,20 @@ export class IgxGridRowPinningPipe implements PipeTransform {

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

public transform(collection: any[] , id: string, pipeTrigger: number) {
public transform(collection: any[] , id: string, isPinned = false, pipeTrigger: number) {
const grid = this.gridAPI.grid;
const pinnedRows = grid.pinnedRecords;
if (pinnedRows.length === 0) {
return collection;

if (!grid.hasPinnedRecords) {
return isPinned ? [] : collection;
}

const result = collection.filter((value, index) => {
return pinnedRows.indexOf(value) === -1;
return isPinned ? grid.isRecordPinned(value) : !grid.isRecordPinned(value);
});
if (isPinned) {
// pinned records should be ordered as they were pinned.
result.sort((rec1, rec2) => grid.pinRecordIndex(rec1) - grid.pinRecordIndex(rec2));
}
return result;
}
}
119 changes: 110 additions & 9 deletions projects/igniteui-angular/src/lib/grids/grid/row-pinning.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ import { configureTestSuite } from '../../test-utils/configure-suite';
import { ColumnPinningPosition, RowPinningPosition } from '../common/enums';
import { IPinningConfig } from '../common/grid.interface';
import { SampleTestData } from '../../test-utils/sample-test-data.spec';
import { IgxGridTransaction } from '../tree-grid';
import { IgxTransactionService } from '../../services';

describe('Row Pinning #grid', () => {
const FIXED_ROW_CONTAINER = '.igx-grid__tr--pinned ';
const CELL_CSS_CLASS = '.igx-grid__td';
configureTestSuite();
let fix;
let grid: IgxGridComponent;

beforeAll(async(() => {
TestBed.configureTestingModule({
declarations: [
GridRowPinningComponent
GridRowPinningComponent,
GridRowPinningWithTransactionsComponent
],
imports: [
NoopAnimationsModule,
Expand All @@ -42,7 +46,7 @@ describe('Row Pinning #grid', () => {
grid.pinRow(fix.componentInstance.data[1]);
fix.detectChanges();

expect(grid.pinnedRecords.length).toBe(1);
expect(grid.pinnedRows.length).toBe(1);
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
expect(pinRowContainer.length).toBe(1);
expect(pinRowContainer[0].children.length).toBe(1);
Expand Down Expand Up @@ -78,7 +82,7 @@ describe('Row Pinning #grid', () => {
grid.pinRow(fix.componentInstance.data[1]);
fix.detectChanges();

expect(grid.pinnedRecords.length).toBe(1);
expect(grid.pinnedRows.length).toBe(1);
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
expect(pinRowContainer.length).toBe(1);
expect(pinRowContainer[0].children.length).toBe(1);
Expand Down Expand Up @@ -138,7 +142,7 @@ describe('Row Pinning #grid', () => {
grid.pinRow(fix.componentInstance.data[1]);
fix.detectChanges();

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

expect(grid.pinnedRecords.length).toBe(0);
expect(grid.pinnedRows.length).toBe(0);
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
expect(pinRowContainer.length).toBe(0);

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

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

expect(grid.pinnedRecords.length).toBe(0);
expect(grid.pinnedRows.length).toBe(0);
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
expect(pinRowContainer.length).toBe(0);

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

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

expect(grid.pinnedRecords.length).toBe(0);
expect(grid.pinnedRows.length).toBe(0);
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
expect(pinRowContainer.length).toBe(0);

expect(grid.getRowByIndex(0).rowID).toBe(fix.componentInstance.data[0]);
expect(grid.getRowByIndex(1).rowID).toBe(fix.componentInstance.data[1]);
});
});

describe(' Editing ', () => {
beforeEach(fakeAsync(() => {
fix = TestBed.createComponent(GridRowPinningWithTransactionsComponent);
fix.detectChanges();
grid = fix.componentInstance.instance;
tick();
fix.detectChanges();
}));

it('should allow pinning edited row.', () => {
grid.updateCell('New value', 'ANTON', 'CompanyName');
fix.detectChanges();
grid.pinRow('ANTON');
fix.detectChanges();

expect(grid.pinnedRows.length).toBe(1);
const pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
expect(pinRowContainer.length).toBe(1);
expect(pinRowContainer[0].children.length).toBe(1);
expect(pinRowContainer[0].children[0].context.rowID).toBe('ANTON');
expect(pinRowContainer[0].children[0].context.rowData.CompanyName).toBe('New value');
});

it('should allow pinning deleted row.', () => {
grid.deleteRow('ALFKI');
fix.detectChanges();
grid.pinRow('ALFKI');
fix.detectChanges();

expect(grid.pinnedRows.length).toBe(1);
const pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
expect(pinRowContainer.length).toBe(1);
expect(pinRowContainer[0].children.length).toBe(1);
expect(pinRowContainer[0].children[0].context.rowID).toBe('ALFKI');
});

it('should allow pinning added row.', () => {

grid.addRow({ 'ID': 'Test', 'CompanyName': 'Test'});
fix.detectChanges();

grid.pinRow('Test');
fix.detectChanges();
expect(grid.pinnedRows.length).toBe(1);
const pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
expect(pinRowContainer.length).toBe(1);
expect(pinRowContainer[0].children.length).toBe(1);
expect(pinRowContainer[0].children[0].context.rowID).toBe('Test');
});

it('should stop editing when edited row is pinned/unpinned.', () => {
grid.getColumnByName('CompanyName').editable = true;
fix.detectChanges();
let cell = grid.getCellByColumn(0, 'CompanyName');
let cellDomNumber = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS))[1];
cellDomNumber.triggerEventHandler('dblclick', {});
fix.detectChanges();

expect(cell.editMode).toBeTruthy();

grid.pinRow(cell.row.rowID);
fix.detectChanges();

cell = grid.getCellByColumn(0, 'CompanyName');
expect(cell.editMode).toBeFalsy();

cellDomNumber = fix.debugElement.queryAll(By.css(CELL_CSS_CLASS))[1];
cellDomNumber.triggerEventHandler('dblclick', {});
fix.detectChanges();

expect(cell.editMode).toBeTruthy();
grid.unpinRow(cell.row.rowID);
fix.detectChanges();
cell = grid.getCellByColumn(0, 'CompanyName');
expect(cell.editMode).toBeFalsy();
});

});
});

@Component({
Expand All @@ -237,3 +320,21 @@ export class GridRowPinningComponent {
@ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true })
public instance: IgxGridComponent;
}


@Component({
template: `
<igx-grid
[pinning]='pinningConfig'
primaryKey='ID'
[width]='"800px"'
[height]='"500px"'
[data]="data"
[autoGenerate]="true">
</igx-grid>
`,
providers: [{ provide: IgxGridTransaction, useClass: IgxTransactionService }]
})
export class GridRowPinningWithTransactionsComponent extends GridRowPinningComponent {
public data = SampleTestData.contactInfoDataFull();
}
2 changes: 1 addition & 1 deletion projects/igniteui-angular/src/lib/grids/row.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class IgxRowDirective<T extends IgxGridBaseDirective & GridType> implemen
* ```
*/
public get pinned(): boolean {
return this.grid.pinnedRecords.indexOf(this.rowData) !== -1;
return this.grid.isRecordPinned(this.rowData);
}
/**
* Sets whether the row is pinned.
Expand Down
6 changes: 3 additions & 3 deletions src/app/grid-column-pinning/grid-column-pinning.sample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ export class GridColumnPinningSampleComponent implements OnInit {

togglePinRow(index) {
const rec = this.data[index];
this.grid1.pinnedRecords.indexOf(rec) === -1 ?
this.grid1.pinRow(this.data[index]) :
this.grid1.unpinRow(this.data[index])
this.grid1.isRecordPinned(rec) ?
this.grid1.pinRow(rec) :
this.grid1.unpinRow(rec)
}

}
Loading