Skip to content

Commit 68daeb9

Browse files
committed
merge: merge master
2 parents 8e7929b + b36b75e commit 68daeb9

20 files changed

+738
-15
lines changed

projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss

+24
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@
7878
@extend %grid-tbody-scrollbar !optional;
7979
}
8080

81+
@include e(tbody-scrollbar-main) {
82+
@extend %grid-tbody-scrollbar-main !optional;
83+
}
84+
85+
@include e(tbody-scrollbar-start) {
86+
@extend %grid-tbody-scrollbar-start !optional;
87+
}
88+
89+
@include e(tbody-scrollbar-end) {
90+
@extend %grid-tbody-scrollbar-end !optional;
91+
}
92+
8193
@include e(scroll) {
8294
@extend %grid-scroll !optional;
8395
}
@@ -317,6 +329,18 @@
317329
@extend %igx-grid__tr--expanded !optional;
318330
}
319331

332+
@include e(tr, $m: pinned) {
333+
@extend %igx-grid__tr--pinned !optional;
334+
}
335+
336+
@include e(tr, $m: pinned-top) {
337+
@extend %igx-grid__tr--pinned-top !optional;
338+
}
339+
340+
@include e(tr, $m: pinned-bottom) {
341+
@extend %igx-grid__tr--pinned-bottom !optional;
342+
}
343+
320344
@include e(tree-grouping-indicator) {
321345
@extend %igx-grid__tree-grouping-indicator !optional;
322346
}

projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss

+26
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,18 @@
943943
position: relative;
944944
}
945945

946+
%grid-tbody-scrollbar-start {
947+
background: --var($theme, 'header-background');
948+
}
949+
950+
%grid-tbody-scrollbar-main {
951+
position: relative;
952+
}
953+
954+
%grid-tbody-scrollbar-end {
955+
background: --var($theme, 'header-background');
956+
}
957+
946958
%grid-scroll-start {
947959
background: --var($theme, 'header-background');
948960
}
@@ -1062,6 +1074,20 @@
10621074
border-bottom: none;
10631075
}
10641076

1077+
%igx-grid__tr--pinned {
1078+
position: relative;
1079+
background: inherit;
1080+
z-index: 10000;
1081+
}
1082+
1083+
%igx-grid__tr--pinned-top {
1084+
border-bottom: map-get($cell-pin, 'style') map-get($cell-pin, 'color') !important;
1085+
}
1086+
1087+
%igx-grid__tr--pinned-bottom {
1088+
border-top: map-get($cell-pin, 'style') map-get($cell-pin, 'color') !important;
1089+
}
1090+
10651091
%igx-grid__tr--edit {
10661092
border-bottom: 1px solid --var($theme, 'edit-mode-color');
10671093
position: relative;

projects/igniteui-angular/src/lib/grids/common/events.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { IBaseEventArgs, CancelableEventArgs } from '../../core/utils';
22
import { IgxBaseExporter, IgxExporterOptionsBase } from '../../services';
33
import { GridKeydownTargetType } from './enums';
44
import { IgxDragDirective } from '../../directives/drag-drop/drag-drop.directive';
5-
import { IGridDataBindable } from './grid.interface';
5+
import { IGridDataBindable, GridType } from './grid.interface';
66
import { IgxGridCellComponent } from '../cell.component';
77
import { IgxColumnComponent } from '../columns/column.component';
88
import { IgxGridBaseDirective } from '../grid-base.directive';
@@ -126,3 +126,21 @@ export interface IRowToggleEventArgs extends IBaseEventArgs {
126126
event?: Event;
127127
cancel: boolean;
128128
}
129+
130+
/**
131+
* Event emitted when a row's pin state changes.
132+
*/
133+
export interface IPinRowEventArgs extends IBaseEventArgs {
134+
/** The row component instance, that was pinned/unpinned.
135+
* May be undefined if row does not exist in the current visible data.
136+
*/
137+
readonly row?: IgxRowDirective<IgxGridBaseDirective & GridType>;
138+
/** The ID of the row, that was pinned/unpinned.
139+
* ID is either the primaryKey value or the data record instance.
140+
*/
141+
readonly rowID: any;
142+
/** The index at which to pin the row in the pinned rows collection. */
143+
insertAtIndex?: number;
144+
/** Whether or noy the row is pinned or unpinned. */
145+
readonly isPinned: boolean;
146+
}

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

+132-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ import {
112112
GridSummaryPosition,
113113
GridSummaryCalculationMode,
114114
FilterMode,
115-
ColumnPinningPosition
115+
ColumnPinningPosition,
116+
RowPinningPosition
116117
} from './common/enums';
117118
import {
118119
IGridCellEventArgs,
@@ -133,7 +134,8 @@ import {
133134
ISearchInfo,
134135
ICellPosition,
135136
IRowToggleEventArgs,
136-
IColumnSelectionEventArgs
137+
IColumnSelectionEventArgs,
138+
IPinRowEventArgs
137139
} from './common/events';
138140
import { IgxAdvancedFilteringDialogComponent } from './filtering/advanced-filtering/advanced-filtering-dialog.component';
139141
import { GridType, IPinningConfig } from './common/grid.interface';
@@ -1388,6 +1390,16 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
13881390
@Output()
13891391
public onRowToggle = new EventEmitter<IRowToggleEventArgs>();
13901392

1393+
/**
1394+
* Emitted when the pinned state of a row is changed.
1395+
* @example
1396+
* ```html
1397+
* <igx-grid [data]="employeeData" (onRowPinning)="rowPin($event)" [autoGenerate]="true"></igx-grid>
1398+
* ```
1399+
*/
1400+
@Output()
1401+
public onRowPinning = new EventEmitter<IPinRowEventArgs>();
1402+
13911403
/**
13921404
* @hidden @internal
13931405
*/
@@ -1632,6 +1644,14 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
16321644
return this.pinning.columns !== ColumnPinningPosition.End;
16331645
}
16341646

1647+
/**
1648+
* @hidden
1649+
* @internal
1650+
*/
1651+
get isRowPinningToTop() {
1652+
return this.pinning.rows !== RowPinningPosition.Bottom;
1653+
}
1654+
16351655
/**
16361656
* @hidden
16371657
* @internal
@@ -1724,6 +1744,12 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
17241744
@ViewChild('tbody', { static: true })
17251745
public tbody: ElementRef;
17261746

1747+
/**
1748+
* @hidden @internal
1749+
*/
1750+
@ViewChild('pinContainer', { static: false })
1751+
public pinContainer: ElementRef;
1752+
17271753
/**
17281754
* @hidden @internal
17291755
*/
@@ -2454,6 +2480,15 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
24542480
protected _columnPinning = false;
24552481

24562482

2483+
/**
2484+
* @hidden
2485+
*/
2486+
public get pinnedRecords() {
2487+
return this._pinnedRecords;
2488+
}
2489+
2490+
protected _pinnedRecords = [];
2491+
24572492
/**
24582493
* @hidden
24592494
*/
@@ -3275,6 +3310,17 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
32753310
return this._pinnedVisible;
32763311
}
32773312

3313+
/**
3314+
* Gets an array of the pinned `IgxRowComponent`s.
3315+
* @example
3316+
* ```typescript
3317+
* const pinnedRow = this.grid.pinnedRows;
3318+
* ```
3319+
*/
3320+
get pinnedRows(): IgxGridRowComponent[] {
3321+
return this.rowList.filter(x => x.pinned);
3322+
}
3323+
32783324
/**
32793325
* Gets an array of unpinned `IgxColumnComponent`s.
32803326
* @example
@@ -4008,6 +4054,87 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
40084054
return col.unpin(index);
40094055
}
40104056

4057+
/**
4058+
* Pin the row by its id.
4059+
* @remarks
4060+
* ID is either the primaryKey value or the data record instance.
4061+
* @example
4062+
* ```typescript
4063+
* this.grid.pinRow(rowID);
4064+
* ```
4065+
* @param rowID The row id - primaryKey value or the data record instance.
4066+
* @param index The index at which to insert the row in the pinned collection.
4067+
*/
4068+
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) {
4071+
return false;
4072+
}
4073+
const row = this.gridAPI.get_row_by_key(rowID);
4074+
4075+
const eventArgs: IPinRowEventArgs = {
4076+
insertAtIndex: index,
4077+
isPinned: true,
4078+
rowID: rowID,
4079+
row: row
4080+
};
4081+
this.onRowPinning.emit(eventArgs);
4082+
4083+
this.pinnedRecords.splice(eventArgs.insertAtIndex || this.pinnedRecords.length, 0, rec);
4084+
this._pipeTrigger++;
4085+
if (this.gridAPI.grid) {
4086+
this.notifyChanges(true);
4087+
}
4088+
}
4089+
4090+
/**
4091+
* Unpin the row by its id.
4092+
* @remarks
4093+
* ID is either the primaryKey value or the data record instance.
4094+
* @example
4095+
* ```typescript
4096+
* this.grid.unpinRow(rowID);
4097+
* ```
4098+
* @param rowID The row id - primaryKey value or the data record instance.
4099+
*/
4100+
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) {
4104+
return false;
4105+
}
4106+
const row = this.gridAPI.get_row_by_key(rowID);
4107+
const eventArgs: IPinRowEventArgs = {
4108+
isPinned: false,
4109+
rowID: rowID,
4110+
row: row
4111+
};
4112+
this.onRowPinning.emit(eventArgs);
4113+
this.pinnedRecords.splice(index, 1);
4114+
this._pipeTrigger++;
4115+
if (this.gridAPI.grid) {
4116+
this.cdr.detectChanges();
4117+
this.notifyChanges(true);
4118+
}
4119+
return true;
4120+
}
4121+
4122+
get pinnedRowHeight() {
4123+
const containerHeight = this.pinContainer ? this.pinContainer.nativeElement.offsetHeight : 0;
4124+
return this.pinnedRecords.length > 0 ? containerHeight : 0;
4125+
}
4126+
4127+
get totalHeight() {
4128+
return this.calcHeight ? this.calcHeight + this.pinnedRowHeight : this.calcHeight;
4129+
}
4130+
4131+
get pinnedBottom() {
4132+
const start = this.verticalScrollContainer.state.startIndex;
4133+
const end = this.verticalScrollContainer.state.startIndex + this.verticalScrollContainer.state.chunkSize - 1;
4134+
const bottom = this.verticalScrollContainer.getScrollForIndex(end, true) - this.verticalScrollContainer.getScrollForIndex(start);
4135+
return bottom;
4136+
}
4137+
40114138

40124139
/**
40134140
* Recalculates grid width/height dimensions.
@@ -4313,6 +4440,9 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
43134440
}
43144441

43154442
this.calcHeight = this._calculateGridBodyHeight();
4443+
if (this.pinnedRowHeight && this.calcHeight) {
4444+
this.calcHeight -= this.pinnedRowHeight;
4445+
}
43164446
}
43174447

43184448
/**

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

+26-4
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,31 @@
101101
<div igxGridBody (keydown.control.c)="copyHandlerIE()" (copy)="copyHandler($event)" class="igx-grid__tbody">
102102
<div class="igx-grid__tbody-content" role="rowgroup" (onDragStop)="selectionService.dragMode = $event" (scroll)='preventContainerScroll($event)'
103103
(onDragScroll)="dragScroll($event)" [igxGridDragSelect]="selectionService.dragMode"
104-
[style.height.px]='calcHeight' [style.width.px]='calcWidth || null' #tbody>
104+
[style.height.px]='totalHeight' [style.width.px]='calcWidth || null' #tbody>
105105
<span *ngIf="hasMovableColumns && draggedColumn && pinnedColumns.length <= 0"
106106
[igxColumnMovingDrop]="headerContainer" [attr.droppable]="true" id="left"
107107
class="igx-grid__scroll-on-drag-left"></span>
108108
<span *ngIf="hasMovableColumns && draggedColumn && pinnedColumns.length > 0"
109109
[igxColumnMovingDrop]="headerContainer" [attr.droppable]="true" id="left"
110110
class="igx-grid__scroll-on-drag-pinned" [style.left.px]="pinnedWidth"></span>
111+
<ng-template #pinnedRecordsTemplate>
112+
<ng-container *ngFor="let rowData of pinnedRecords
113+
| visibleColumns:hasVisibleColumns
114+
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
115+
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
116+
| gridDetails:hasDetails:expansionStates:pipeTrigger; let rowIndex = index">
117+
<ng-container *ngTemplateOutlet="getRowTemplate(rowData); context: getContext(rowData, rowIndex, true)">
118+
</ng-container>
119+
</ng-container>
120+
</ng-template>
121+
<div #pinContainer *ngIf='pinnedRecords.length > 0 && isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-top'>
122+
<ng-container *ngTemplateOutlet="pinnedRecordsTemplate">
123+
</ng-container>
124+
</div>
111125
<ng-template igxGridFor let-rowData [igxGridForOf]="data
112126
| gridTransaction:id:pipeTrigger
113127
| visibleColumns:hasVisibleColumns
128+
| rowPinning:id:pipeTrigger
114129
| gridFiltering:filteringExpressionsTree:filterStrategy:advancedFilteringExpressionsTree:id:pipeTrigger:filteringPipeTrigger
115130
| gridSort:sortingExpressions:sortStrategy:id:pipeTrigger
116131
| gridGroupBy:groupingExpressions:groupingExpansionState:groupsExpanded:id:groupsRecords:pipeTrigger
@@ -131,6 +146,10 @@
131146
(onBeforeViewDetach)='viewDetachHandler($event)'>
132147
</ng-template>
133148
</ng-template>
149+
<div #pinContainer *ngIf='pinnedRecords.length > 0 && !isRowPinningToTop' class='igx-grid__tr--pinned igx-grid__tr--pinned-bottom' [style.bottom.px]='pinnedBottom'>
150+
<ng-container *ngTemplateOutlet="pinnedRecordsTemplate">
151+
</ng-container>
152+
</div>
134153
<ng-template #record_template let-rowIndex="index" let-rowData>
135154
<igx-grid-row [gridID]="id" [index]="rowIndex" [rowData]="rowData" #row>
136155
</igx-grid-row>
@@ -170,9 +189,12 @@
170189
</div>
171190
<span *ngIf="hasMovableColumns && draggedColumn" [igxColumnMovingDrop]="headerContainer" [attr.droppable]="true"
172191
id="right" class="igx-grid__scroll-on-drag-right"></span>
173-
<div [hidden]='!hasVerticalSroll()' class="igx-grid__tbody-scrollbar" [style.width.px]="scrollWidth"
174-
[style.height.px]='calcHeight'>
175-
<ng-template igxGridFor [igxGridForOf]='[]' #verticalScrollHolder></ng-template>
192+
<div [hidden]='!hasVerticalSroll()' class="igx-grid__tbody-scrollbar" [style.width.px]="scrollWidth">
193+
<div class="igx-grid__tbody-scrollbar-start" [style.height.px]=' isRowPinningToTop ? pinnedRowHeight : 0'></div>
194+
<div class="igx-grid__tbody-scrollbar-main" [style.height.px]='calcHeight'>
195+
<ng-template igxGridFor [igxGridForOf]='[]' #verticalScrollHolder></ng-template>
196+
</div>
197+
<div class="igx-grid__tbody-scrollbar-end" [style.height.px]='!isRowPinningToTop ? pinnedRowHeight : 0'></div>
176198
</div>
177199
</div>
178200

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,11 @@ export class IgxGridComponent extends IgxGridBaseDirective implements GridType,
826826
/**
827827
* @hidden @internal
828828
*/
829-
public getContext(rowData, rowIndex): any {
829+
public getContext(rowData: any, rowIndex: number, pinned?: boolean): any {
830+
if (pinned && !this.isRowPinningToTop) {
831+
rowIndex = rowIndex + this.dataView.length;
832+
}
833+
rowIndex = !pinned && this.isRowPinningToTop ? rowIndex + this.pinnedRecords.length : rowIndex;
830834
if (this.isDetailRecord(rowData)) {
831835
const cachedData = this.childDetailTemplates.get(rowData.detailsData);
832836
const rowID = this.primaryKey ? rowData.detailsData[this.primaryKey] : this.data.indexOf(rowData.detailsData);

0 commit comments

Comments
 (0)