Skip to content

Commit f13b418

Browse files
author
MPopov
committed
Merge remote-tracking branch 'origin/mpopov/active-styles' into mpopov/active-styles
2 parents 3e41a5a + 178c382 commit f13b418

14 files changed

+98
-25
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ All notable changes for each version of this project will be documented in this
6464
- `deselectColumns` API method is added for the `IgxGrid`. It allows to deselect columns by passing array of IgxColumnComponent or column fields.
6565
- `deselectAllColumns` API method is added for the `IgxGrid`. It allows to deselect all columns.
6666
- `getSelectedColumnsData` API method is added for the `IgxGrid`. It allows to get the selected columns data.
67+
Added keyBoard navigation support in the IgxGrid headers. Now is possible to navigate with the arrows keys through grid headers. Also we provide a number of key combinations that trigger a different column functionality like filtering, sorting, grouping and etc. You can read more information in the [Grid Specification](https://github.com/IgniteUI/igniteui-angular/wiki/igxGrid-Specification#kb-navigation).
68+
- **Behavioral Change**
69+
- *you can not use* `tab` key to navigate between the cell in the Igx Grid. The navigation is performed only with arrow keys.
70+
- when you are in edit mode with `tab` key you can navigate to the next editable cell.
71+
- `page up` and `page down` keys will perform action only if the focused element is the tbody of the grid.
72+
- The grid introduces the following basic `tab stops`:
73+
- Toolbar / Group by Area if existing;
74+
- The first cell in the header row;
75+
- The first cell in the first body row;
76+
- The first cell in column summary if exists;
77+
- Pager UI;
78+
- `onGridKeydown` event is deprecated. Now you can directly bind to keydown on the IgxGrid component in order to perform custom keyboard navigation.
6779

6880
- `IgxCombo`:
6981
- Added `autoFocusSearch` input that allows to manipulate the combo's opening behavior. When the property is `true` (by default), the combo's search input is focused on open. When set to `false`, the focus goes to the combo items container, which can be used to prevent the software keyboard from activating on mobile devices when opening the combo.

projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { IForOfState } from '../../directives/for-of/for_of.directive';
1010
import { IgxColumnComponent } from '../columns/column.component';
1111
import { IFilteringOperation } from '../../data-operations/filtering-condition';
1212
import { GridBaseAPIService } from '../api.service';
13-
import { IColumnVisibilityChangedEventArgs } from '../grid';
1413
import { IColumnResizeEventArgs } from '../common/events';
1514
import { GridType } from '../common/grid.interface';
1615
import { IgxDatePipeComponent } from '../common/pipes';
@@ -20,7 +19,6 @@ import { useAnimation } from '@angular/animations';
2019
import { fadeIn, fadeOut } from '../../animations/main';
2120
import { ExcelStylePositionStrategy } from './excel-style/excel-style-position-strategy';
2221
import { AbsoluteScrollStrategy } from '../../services/overlay/scroll/absolute-scroll-strategy';
23-
import { IgxGridExcelStyleFilteringComponent } from './excel-style/grid.excel-style-filtering.component';
2422

2523
const FILTERING_ICONS_FONT_SET = 'filtering-icons';
2624

@@ -69,7 +67,7 @@ export class IgxFilteringService implements OnDestroy {
6967
this.destroy$.complete();
7068
}
7169

72-
public toggleFilterDropdown(element, column) {
70+
public toggleFilterDropdown(element, column, classRef) {
7371
if (!this._componentOverlayId || (this.column && this.column.field !== column.field)) {
7472
this.column = column;
7573
const filterIcon = this.column.filteringExpressionsTree ? 'igx-excel-filter__icon--filtered' : 'igx-excel-filter__icon';
@@ -78,7 +76,7 @@ export class IgxFilteringService implements OnDestroy {
7876
this._filterMenuOverlaySettings.positionStrategy.settings.target = filterIconTarget;
7977
this._filterMenuOverlaySettings.outlet = (this.grid as any).outlet;
8078
this._componentOverlayId =
81-
this._overlayService.attach(IgxGridExcelStyleFilteringComponent, this._filterMenuOverlaySettings, this._moduleRef);
79+
this._overlayService.attach(classRef, this._filterMenuOverlaySettings, this._moduleRef);
8280
this._overlayService.show(this._componentOverlayId, this._filterMenuOverlaySettings);
8381
}
8482
}
@@ -98,7 +96,7 @@ export class IgxFilteringService implements OnDestroy {
9896
this._overlayService.onOpening.pipe(
9997
filter((overlay) => overlay.id === this._componentOverlayId),
10098
takeUntil(this.destroy$)).subscribe((eventArgs) => {
101-
const instance = eventArgs.componentRef.instance as IgxGridExcelStyleFilteringComponent;
99+
const instance = eventArgs.componentRef.instance as any;
102100
if (instance) {
103101
instance.initialize(this.column, this._overlayService, eventArgs.id);
104102
}

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

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,6 +1509,9 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
15091509
@ViewChildren('row')
15101510
private _rowList: QueryList<IgxGridRowComponent>;
15111511

1512+
@ViewChildren('pinnedRow')
1513+
private _pinnedRowList: QueryList<IgxGridRowComponent>;
1514+
15121515
@ViewChildren('summaryRow', { read: IgxSummaryRowComponent })
15131516
protected _summaryRowList: QueryList<IgxSummaryRowComponent>;
15141517

@@ -1754,8 +1757,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
17541757
/**
17551758
* @hidden @internal
17561759
*/
1757-
@ViewChildren('pinContainer', { read: ElementRef })
1758-
public pinContainers: QueryList<ElementRef>;
1760+
@ViewChild('pinContainer', { read: ElementRef })
1761+
public pinContainer: ElementRef;
17591762

17601763
/**
17611764
* @hidden @internal
@@ -2548,6 +2551,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
25482551

25492552

25502553
private columnListDiffer;
2554+
private rowListDiffer;
25512555
private _hiddenColumnsText = '';
25522556
private _pinnedColumnsText = '';
25532557
private _height = '100%';
@@ -2888,6 +2892,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
28882892
super.ngOnInit();
28892893
this._setupServices();
28902894
this._setupListeners();
2895+
this.rowListDiffer = this.differs.find([]).create(null);
28912896
this.columnListDiffer = this.differs.find([]).create(null);
28922897
this.calcWidth = this.width && this.width.indexOf('%') === -1 ? parseInt(this.width, 10) : 0;
28932898
this.shouldGenerate = this.autoGenerate;
@@ -3045,11 +3050,11 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
30453050

30463051
const vertScrDC = this.verticalScrollContainer.displayContainer;
30473052
vertScrDC.addEventListener('scroll', this.scrollHandler);
3048-
this.pinContainers.changes.subscribe((c) => {
3049-
if (this.hasPinnedRecords) {
3050-
// on row pin containers change grid sizes should be recalculated.
3051-
this.calculateGridSizes();
3052-
}
3053+
3054+
this._pinnedRowList.changes
3055+
.pipe(takeUntil(this.destroy$))
3056+
.subscribe((change: QueryList<IgxGridRowComponent>) => {
3057+
this.onPinnedRowsChanged(change);
30533058
});
30543059
}
30553060

@@ -3430,7 +3435,9 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
34303435
* ```
34313436
*/
34323437
get pinnedRows(): IgxGridRowComponent[] {
3433-
return this.rowList.filter(x => x.pinned && !x.disabled);
3438+
return this._pinnedRowList.toArray().sort((a, b) => {
3439+
return a.index - b.index;
3440+
});
34343441
}
34353442

34363443
/**
@@ -4206,7 +4213,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
42064213
this._pinnedRecordIDs.splice(insertIndex, 0, rowID);
42074214
this._pipeTrigger++;
42084215
if (this.gridAPI.grid) {
4209-
this.notifyChanges(true);
4216+
this.notifyChanges();
42104217
}
42114218
}
42124219

@@ -4237,14 +4244,12 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
42374244
this._pipeTrigger++;
42384245
if (this.gridAPI.grid) {
42394246
this.cdr.detectChanges();
4240-
this.notifyChanges(true);
42414247
}
42424248
return true;
42434249
}
42444250

42454251
get pinnedRowHeight() {
4246-
const pinContainer = this.pinContainers && this.pinContainers.length > 0 ? this.pinContainers.first : null;
4247-
const containerHeight = pinContainer ? pinContainer.nativeElement.offsetHeight : 0;
4252+
const containerHeight = this.pinContainer ? this.pinContainer.nativeElement.offsetHeight : 0;
42484253
return this.hasPinnedRecords ? containerHeight : 0;
42494254
}
42504255

@@ -4818,6 +4823,16 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements
48184823
0 : this.defaultTargetBodyHeight;
48194824
}
48204825

4826+
/**
4827+
* @hidden @internal
4828+
*/
4829+
protected onPinnedRowsChanged(change: QueryList<IgxGridRowComponent>) {
4830+
const diff = this.rowListDiffer.diff(change);
4831+
if (diff) {
4832+
this.notifyChanges(true);
4833+
}
4834+
}
4835+
48214836
/**
48224837
* @hidden
48234838
*/

projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { IgxGridBaseDirective } from './grid-base.directive';
77
import { IMultiRowLayoutNode } from './selection/selection.service';
88
import { GridKeydownTargetType, GridSelectionMode, FilterMode } from './common/enums';
99
import { SortingDirection } from '../data-operations/sorting-expression.interface';
10+
import { IgxGridExcelStyleFilteringComponent } from './filtering/excel-style/grid.excel-style-filtering.component';
1011
export interface ColumnGroupsCache {
1112
level: number;
1213
visibleIndex: number;
@@ -169,7 +170,7 @@ export class IgxGridNavigationService {
169170
if (ctrl && shift && key === 'l' && this.grid.allowFiltering && !column.columnGroup && column.filterable) {
170171
if (this.grid.filterMode === FilterMode.excelStyleFilter) {
171172
const headerEl = this.grid.nativeElement.querySelector(`.igx-grid__th--active`);
172-
this.grid.filteringService.toggleFilterDropdown(headerEl, column);
173+
this.grid.filteringService.toggleFilterDropdown(headerEl, column, IgxGridExcelStyleFilteringComponent);
173174
} else {
174175
this.performHorizontalScrollToCell(column.visibleIndex);
175176
this.grid.filteringService.filteredColumn = column;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<ng-container *ngIf="showExpanderIndicator">
3232
<div #indicator
3333
class="igx-grid__tree-grouping-indicator"
34-
(click)="toggle($event)" (focus)="onIndicatorFocus()" tabindex="-1">
34+
(click)="toggle($event)" (focus)="onIndicatorFocus()">
3535
<ng-container *ngTemplateOutlet="iconTemplate; context: { $implicit: this }">
3636
</ng-container>
3737
</div>

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ describe('Row Pinning #grid', () => {
7777
expect(grid.getRowByIndex(2).rowID).toBe(fix.componentInstance.data[0]);
7878
expect(grid.getRowByIndex(5).rowID).toBe(fix.componentInstance.data[3]);
7979

80+
fix.detectChanges();
8081
// 2 records pinned + 2px border
8182
expect(grid.pinnedRowHeight).toBe(2 * grid.renderedRowHeight + 2);
8283
const expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
@@ -111,7 +112,7 @@ describe('Row Pinning #grid', () => {
111112
expect(pinRowContainer[0].children.length).toBe(2);
112113
expect(pinRowContainer[0].children[0].context.rowID).toBe(fix.componentInstance.data[1]);
113114
expect(pinRowContainer[0].children[1].context.rowID).toBe(fix.componentInstance.data[0]);
114-
115+
fix.detectChanges();
115116
// check last pinned is fully in view
116117
const last = pinRowContainer[0].children[1].context.nativeElement;
117118
expect(last.getBoundingClientRect().bottom - grid.tbody.nativeElement.getBoundingClientRect().bottom).toBe(0);
@@ -381,6 +382,7 @@ describe('Row Pinning #grid', () => {
381382
let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
382383
expect(pinRowContainer.length).toBe(1);
383384

385+
fix.detectChanges();
384386
let expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
385387
expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1);
386388

@@ -390,6 +392,7 @@ describe('Row Pinning #grid', () => {
390392
pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER));
391393
expect(pinRowContainer.length).toBe(0);
392394

395+
fix.detectChanges();
393396
expect(grid.pinnedRowHeight).toBe(0);
394397
expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
395398
expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1);
@@ -805,11 +808,37 @@ describe('Row Pinning #grid', () => {
805808
expect(grid.getRowByIndex(2).rowID).toBe(fix.componentInstance.data[1]);
806809
expect(grid.getRowByIndex(3).rowID).toBe(fix.componentInstance.data[2]);
807810

811+
fix.detectChanges();
808812
// 1 records pinned + 2px border
809813
expect(grid.pinnedRowHeight).toBe(grid.renderedRowHeight + 2);
810814
const expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
811815
expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1);
812816
});
817+
818+
it('should keep the scrollbar sizes correct when partially filtering out pinned records', () => {
819+
grid.getRowByIndex(1).pin();
820+
fix.detectChanges();
821+
grid.getRowByIndex(3).pin();
822+
fix.detectChanges();
823+
grid.getRowByIndex(5).pin();
824+
fix.detectChanges();
825+
grid.getRowByIndex(7).pin();
826+
fix.detectChanges();
827+
828+
fix.detectChanges();
829+
// 4 records pinned + 2px border
830+
expect(grid.pinnedRowHeight).toBe(4 * grid.renderedRowHeight + 2);
831+
let expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
832+
expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1);
833+
834+
grid.filter('ContactTitle', 'Owner', IgxStringFilteringOperand.instance().condition('contains'), false);
835+
fix.detectChanges();
836+
837+
// 2 records pinned + 2px border
838+
expect(grid.pinnedRowHeight).toBe(2 * grid.renderedRowHeight + 2);
839+
expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight;
840+
expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1);
841+
});
813842
});
814843
});
815844

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@
125125
}"
126126
class='igx-grid__tr--pinned' [style.bottom.px]=' !isRowPinningToTop ? pinnedBottom : null'>
127127
<ng-container *ngFor="let rowData of pinnedData; let rowIndex = index">
128-
<ng-container *ngTemplateOutlet="getRowTemplate(rowData); context: getContext(rowData, rowIndex, true)">
128+
<ng-container *ngTemplateOutlet="pinned_record_template; context: getContext(rowData, rowIndex, true)">
129129
</ng-container>
130130
</ng-container>
131131
</div>
@@ -160,6 +160,10 @@
160160
<igx-grid-row [gridID]="id" [index]="rowIndex" [rowData]="rowData" [disabled]="disabledRow" #row>
161161
</igx-grid-row>
162162
</ng-template>
163+
<ng-template #pinned_record_template let-rowIndex="index" let-rowData>
164+
<igx-grid-row [gridID]="id" [index]="rowIndex" [rowData]="rowData" #row #pinnedRow>
165+
</igx-grid-row>
166+
</ng-template>
163167
<ng-template #group_template let-rowIndex="index" let-rowData>
164168
<igx-grid-groupby-row [gridID]="id" [index]="rowIndex" [groupRow]="rowData" #row>
165169
</igx-grid-groupby-row>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { IgxColumnResizingService } from '../resizing/resizing.service';
2020
import { Subject } from 'rxjs';
2121
import { GridType } from '../common/grid.interface';
2222
import { GridSelectionMode } from '../common/enums';
23+
import { IgxGridExcelStyleFilteringComponent } from '../filtering/excel-style/grid.excel-style-filtering.component';
2324

2425
/**
2526
* @hidden
@@ -182,7 +183,7 @@ export class IgxGridHeaderComponent implements DoCheck, OnInit, OnDestroy {
182183

183184

184185
public onFilteringIconClick(event) {
185-
this.grid.filteringService.toggleFilterDropdown(this.elementRef.nativeElement, this.column);
186+
this.grid.filteringService.toggleFilterDropdown(this.elementRef.nativeElement, this.column, IgxGridExcelStyleFilteringComponent);
186187
}
187188

188189
get grid(): any {

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
[ngClass]="{ 'igx-grid__tr--pinned-bottom': !isRowPinningToTop, 'igx-grid__tr--pinned-top': isRowPinningToTop }"
105105
[style.bottom.px]=' !isRowPinningToTop ? pinnedBottom : null'>
106106
<ng-container *ngFor="let rowData of pinnedData; let rowIndex = index">
107-
<ng-container *ngTemplateOutlet="hierarchical_record_template; context: getContext(rowData, rowIndex, true)">
107+
<ng-container *ngTemplateOutlet="pinned_hierarchical_record_template; context: getContext(rowData, rowIndex, true)">
108108
</ng-container>
109109
</ng-container>
110110
</div>
@@ -134,6 +134,11 @@
134134
<igx-hierarchical-grid-row [gridID]="id" [index]="rowIndex" [disabled]="disabledRow" [rowData]="rowData" #row>
135135
</igx-hierarchical-grid-row>
136136
</ng-template>
137+
138+
<ng-template #pinned_hierarchical_record_template let-rowIndex="index" let-rowData>
139+
<igx-hierarchical-grid-row [gridID]="id" [index]="rowIndex" [rowData]="rowData" #row #pinnedRow>
140+
</igx-hierarchical-grid-row>
141+
</ng-template>
137142
<ng-template #child_record_template let-rowIndex="index" let-rowData>
138143
<div style="overflow:auto;width: 100%;" [attr.data-rowindex]='rowIndex' (scroll)='onContainerScroll()'
139144
[ngClass]="{

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => {
796796
expect(hierarchicalGrid.getRowByIndex(3).rowID).toBe('1');
797797
expect(hierarchicalGrid.getRowByIndex(4).rowID).toBe('2');
798798

799+
fixture.detectChanges();
799800
expect(hierarchicalGrid.pinnedRowHeight).toBe(2 * hierarchicalGrid.renderedRowHeight + 2);
800801
const expectedHeight = parseInt(hierarchicalGrid.height, 10) -
801802
hierarchicalGrid.pinnedRowHeight - 18 - hierarchicalGrid.theadRow.nativeElement.offsetHeight;
@@ -838,6 +839,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => {
838839
expect(hierarchicalGrid.getRowByIndex(1).rowID).toBe('1');
839840
expect(hierarchicalGrid.getRowByIndex(2).rowID).toBe('2');
840841

842+
fixture.detectChanges();
841843
// Check last pinned is fully in view
842844
const last = pinRowContainer[0].children[1].context.nativeElement;
843845
expect(last.getBoundingClientRect().bottom - hierarchicalGrid.tbody.nativeElement.getBoundingClientRect().bottom).toBe(0);

projects/igniteui-angular/src/lib/grids/state.directive.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ describe('IgxGridState - input properties #grid', () => {
416416
expect(gridState).toBe(rowPinState);
417417

418418
grid.getRowByIndex(3).pin();
419+
fix.detectChanges();
419420

420421
state.setState(rowPinStateObject);
421422
fix.detectChanges();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
*ngIf="!isLoading"
3737
class="igx-grid__tree-grouping-indicator"
3838
[ngStyle]="{'visibility': showIndicator ? 'visible' : 'hidden'}"
39-
(click)="toggle($event)" (focus)="onIndicatorFocus()" tabindex="-1">
39+
(click)="toggle($event)" (focus)="onIndicatorFocus()">
4040
<ng-container *ngTemplateOutlet="iconTemplate; context: { $implicit: this }">
4141
</ng-container>
4242
<ng-container *ngTemplateOutlet="pinnedIndicatorTemplate; context: context">

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,7 @@ describe('IgxTreeGrid - Integration #tGrid', () => {
14731473

14741474
treeGrid.pinRow(rowToPin.rowData[primaryKey]);
14751475
fix.detectChanges();
1476+
fix.detectChanges();
14761477

14771478
const firstColumnField = treeGrid.columns[0].field;
14781479
const pinnedChipPosition = treeGrid.getCellByColumn(1, firstColumnField);

0 commit comments

Comments
 (0)