Skip to content
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

Extend Grid API to allow custom keyboard navigation #4646

Merged
merged 45 commits into from
May 10, 2019
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
1d8cbb6
chore(IgxCell): remove unnecessary blur from cell
ddincheva Apr 11, 2019
2df3da1
refactor(GridNavigation): add check if vertical scroll will be performed
ddincheva Apr 11, 2019
95c2d07
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva Apr 12, 2019
452dcae
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva Apr 15, 2019
0816d58
chore(IgxGroupByRow): go to first cell if activeEl column is hidden
ddincheva Apr 15, 2019
26afde1
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva Apr 18, 2019
851f47e
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva Apr 19, 2019
15aa10e
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva Apr 22, 2019
494d126
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva Apr 23, 2019
0c21a5f
chore(IgxGrid): calc should prerform vertical scroll
ddincheva Apr 23, 2019
23cab5c
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva Apr 23, 2019
2ed6f14
feat(IgxGroupByRow): refactored keydown and emit the new gridKeyDown …
ddincheva Apr 24, 2019
4145824
refactor(SummaryCell): prevent handle not supported keys in summary c…
ddincheva Apr 24, 2019
5dd1cd6
feat(IgxGrid): emit onGridKeydown event to allow custom keyboard nav …
ddincheva Apr 24, 2019
6ba7ad9
feat(IgxGrid): add navigateTo method to allow custom KB navigation #4054
ddincheva Apr 24, 2019
c608a6b
feat(IgxCell): emit onGridKeydown event #4054
ddincheva Apr 24, 2019
ab993df
chore(*): add custom keyboard navigation to editing sample
ddincheva Apr 24, 2019
76ae131
merge 7.2.x
ddincheva Apr 24, 2019
3379720
chore(igxGrid): fix linting errors
ddincheva Apr 24, 2019
2efe631
chore(IgxCell): prevent default on keydown alt
ddincheva Apr 25, 2019
6abb77f
Merge branch '7.2.x' into ddincheva/customKBNav
ddincheva Apr 25, 2019
b787a7d
Merge branch '7.2.x' into ddincheva/customKBNav
ddincheva Apr 30, 2019
5eea2ae
Merge branch '7.2.x' into ddincheva/customKBNav
ddincheva May 2, 2019
e67e3d5
Merge branch '7.2.x' into ddincheva/customKBNav
ddincheva May 2, 2019
e6d0214
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva May 3, 2019
fe8753c
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva May 7, 2019
5e62fe8
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva May 7, 2019
4304208
feat(IgxGrid): deprecate onFocusChange event #4054
ddincheva May 7, 2019
c1ddc3c
test(IgxGrid): add test for navigateTo method #4054
ddincheva May 7, 2019
2a8a2b8
chore(*): update the changelog with the newly added KB navigation API
ddincheva May 7, 2019
541a7ca
Merge branch '7.2.x' into ddincheva/customKBNav
ddincheva May 8, 2019
6e24aca
Merge branch '7.2.x' of https://github.com/IgniteUI/igniteui-angular …
ddincheva May 8, 2019
2c6179b
Merge branch 'ddincheva/customKBNav' of https://github.com/IgniteUI/i…
ddincheva May 8, 2019
63827af
Merge branch '7.2.x' into ddincheva/customKBNav
ddincheva May 8, 2019
9b68d7b
Merge branch 'ddincheva/customKBNav' of https://github.com/IgniteUI/i…
ddincheva May 8, 2019
d72368c
chore(IgxGrid): address the requested changes
ddincheva May 8, 2019
b665477
chore(*): update the description of navigateTo method
ddincheva May 9, 2019
18ade19
fix(IgxGrid): add validation to getPrevious/Next cell methods #4054
ddincheva May 9, 2019
7df61af
test(IgxGridComponent): add basic tests for getNext/Previous cell met…
ddincheva May 9, 2019
4fc2a88
chore(*): sort the visible column list
ddincheva May 9, 2019
a57233d
Merge branch '7.2.x' into ddincheva/customKBNav
ddincheva May 9, 2019
05cb0ae
Merge branch 'ddincheva/customKBNav' of https://github.com/IgniteUI/i…
ddincheva May 9, 2019
4ba73fb
chore(*): additional check to return correctly next/prev cell
ddincheva May 10, 2019
78c9df4
chore(*): check for groupBy row and summary
ddincheva May 10, 2019
1af97d1
Merge branch '7.2.x' into ddincheva/customKBNav
zdrawku May 10, 2019
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
23 changes: 16 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@

All notable changes for each version of this project will be documented in this file.

##7.2.8
- `IgxGrid` Custom keyboard navigation
- `onFocusChange` event is deprecated.
- `onGridKeydown` is exposed. The event will emit
`IGridKeydownEventArgs { targetType: GridKeydownTargetType; target: Object; event: Event; cancel: boolean; }`
- `navigateTo(rowIndex: number, visibleColumnIndex: number, callback({targetType, target: Object }))` - this method allows you to navigate to a randon position in the grid;
Copy link
Contributor

@zdrawku zdrawku May 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `navigateTo(rowIndex: number, visibleColumnIndex: number, callback({targetType, target: Object }))` - this method allows you to navigate to a randon position in the grid;
- `navigateTo(rowIndex: number, visibleColumnIndex: number, callback({targetType, target: Object }))` - this method allows you to navigate to a position in the grid based on provided `rowindex` and `visibleColumnIndex`;

- `getNextCell(currentRowIndex, currentvisibleColumnIndex, callback(IgxColumnComponent))` - returns `{ rowIndex, visibleColumnIndex }` which defines the next cell, that match specific criteria according to the current position
- `getPreviousCell(currentRowIndex, currentvisibleColumnIndex, callback(IgxColumnComponent))` - returns `{ rowIndex, visibleColumnIndex }` which defines the previous cell, that match specific criteria according to the current position

## 7.2.6
- `igxGrid`
- **Feature** The `groupsRecords` property now returns the full grouping tree as in 7.1 and also includes the grouping information for all pages.

## 7.2.5
- `igxDrop`
- `igxDrop`
- `onEnter`, `onLeave` and `onDrop` events now have new arguments for `originalEvent`, `offsetX` and `offsetY` relative to the container the igxDrop is instanced.
- `IgxList`
- **Feature** the `index` property is now an `@Input` and can be assigned by structural directives such as `*igxFor`.
Expand Down Expand Up @@ -40,9 +49,9 @@ All notable changes for each version of this project will be documented in this
### New feature
- [Multi-cell selection](https://github.com/IgniteUI/igniteui-angular/wiki/Grid-Multi-cell-selection-Specification) - Enables range selection of cells in the grid.

### Grids Performance improvements
### Grids Performance improvements
- Grid rendering speed
- Grid grouping rendering speed
- Grid grouping rendering speed
- Grid vertical scrolling using the scroll arrows
- Grid horizontal scrolling using the scroll arrows
- Grid cell focusing time
Expand Down Expand Up @@ -81,7 +90,7 @@ All notable changes for each version of this project will be documented in this
- Update child summaries correctly when CRUD operations are performed #4408
- Add igxQuickFilterTemplate directive #4377
- Resizing: move resize handle logic in a directive #4378
- No event emitted when column is unpinned #3799
- No event emitted when column is unpinned #3799
- When update a cell in the grouped column the child summaries are not updated #4324
- Column Group border is misaligned with its children's in some cases #4387
- Expanding last row of HierarchicalGrid via keyboard(Alt + downArrow) leads to cell losing its focus. #4080
Expand All @@ -92,7 +101,7 @@ All notable changes for each version of this project will be documented in this
## 7.2.2
### Features
- **Components' Display Type** - All components now have their CSS display property explicitly set on the host element to ensure width, padding, and margins are applied when set directly on the host selectors.
- **Themes**
- **Themes**
- Add support for gradients and images as values for component themes via the component theme functions.
- `Palettes` - added surface color to the palette. The surface color is used by cards, pickers, dialog windows, etc. as the default background.

Expand Down Expand Up @@ -317,13 +326,13 @@ All notable changes for each version of this project will be documented in this
- IgxCombo - Keyboard navigation ArrowDown stutters on chunk load #3999
- Row editing overlay banner not shown when enter row editing #4117
- IgxToggle open method always tries to get id even when it has one #3971
- Last (right-aligned) column is cut off when no widths are set for the columns #3396
- Last (right-aligned) column is cut off when no widths are set for the columns #3396
- The selection in the last grid column does not span in the whole cell. #1115
- Last column header is a bit wider than the cells #1230

## 7.1.11
### Improvements
- Row and Cell editing Docs improvements #4055
- Row and Cell editing Docs improvements #4055

## 7.1.10
### Features
Expand Down
24 changes: 11 additions & 13 deletions projects/igniteui-angular/src/lib/grids/cell.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,6 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy {
}

protected handleEnd(ctrl: boolean) {
this.nativeElement.blur();
if (ctrl) {
this.grid.navigation.goToLastCell();
} else {
Expand All @@ -756,7 +755,6 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy {
}

protected handleHome(ctrl: boolean) {
this.nativeElement.blur();
if (ctrl) {
this.grid.navigation.goToFirstCell();
} else {
Expand All @@ -780,22 +778,27 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy {
if (!SUPPORTED_KEYS.has(key)) {
return;
}
event.stopPropagation();

const keydownArgs = { targetType: 'dataCell', target: this, event: event, cancel: false };
this.grid.onGridKeydown.emit(keydownArgs);
if (keydownArgs.cancel) {
this.selectionService.keyboardStateOnKeydown(node, shift, shift && key === 'tab');
return;
}

if (event.altKey) {
event.preventDefault();
this.handleAlt(key, event);
return;
}

this.selectionService.keyboardStateOnKeydown(node, shift, shift && key === 'tab');


if (key === 'tab') {
event.preventDefault();
event.stopPropagation();
}

if (this.editMode) {
event.stopPropagation();
if (NAVIGATION_KEYS.has(key)) {
if (this.column.inlineEditorTemplate) { return; }
if (['date', 'boolean'].indexOf(this.column.dataType) > -1) { return; }
Expand All @@ -805,16 +808,11 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy {

if (NAVIGATION_KEYS.has(key)) {
event.preventDefault();
event.stopPropagation();
}

// TODO: to be deleted when onFocusChange event is removed #4054
const args = { cell: this, groupRow: null, event: event, cancel: false };

this.grid.onFocusChange.emit(args);

if (args.cancel) {
return;
}
if (args.cancel) { return; }

switch (key) {
case 'tab':
Expand Down
146 changes: 137 additions & 9 deletions projects/igniteui-angular/src/lib/grids/grid-base.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ import { IGridResourceStrings } from '../core/i18n/grid-resources';
import { CurrentResourceStrings } from '../core/i18n/resources';
import { IgxGridSummaryService } from './summaries/grid-summary.service';
import { IgxSummaryRowComponent } from './summaries/summary-row.component';
import { DeprecateMethod } from '../core/deprecateDecorators';
import { DeprecateMethod, DeprecateProperty } from '../core/deprecateDecorators';
import { IgxGridSelectionService, GridSelectionRange, IgxGridCRUDService, IgxRow, IgxCell } from '../core/grid-selection';
import { DragScrollDirection } from './drag-select.directive';
import { ICachedViewLoadedEventArgs } from '../directives/template-outlet/template_outlet.directive';
Expand Down Expand Up @@ -173,13 +173,20 @@ export interface IColumnMovingEndEventArgs {
source: IgxColumnComponent;
target: IgxColumnComponent;
}

// TODO: to be deleted when onFocusChange event is removed #4054
export interface IFocusChangeEventArgs {
cell: IgxGridCellComponent;
event: Event;
cancel: boolean;
}

export interface IGridKeydownEventArgs {
targetType: GridKeydownTargetType;
target: Object;
event: Event;
cancel: boolean;
}

export interface IGridDataBindable {
data: any[];
filteredData: any[];
Expand All @@ -201,6 +208,12 @@ export enum FilterMode {
excelStyleFilter = 'excelStyleFilter'
}

export enum GridKeydownTargetType {
dataCell = 'dataCell',
summaryCell = 'summaryCell',
groupRow = 'groupRow'
}

export abstract class IgxGridBaseComponent extends DisplayDensityBase implements OnInit, OnDestroy, AfterContentInit, AfterViewInit {
private _scrollWidth: number;

Expand Down Expand Up @@ -1431,19 +1444,27 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
public onColumnMovingEnd = new EventEmitter<IColumnMovingEndEventArgs>();

/**
* Emitted when changing the focus while navigating with the keyboard.
* Return the focused cell or focused group row. This event is cancelable.
* @deprecated you should use onGridKeydown event
*/
@Output()
@DeprecateProperty('onFocusChange event is deprecated. Use onGridKeydown event instead.')
public onFocusChange = new EventEmitter<IFocusChangeEventArgs>();

/**
* Emitted when keydown is triggered over element inside grid's body.
* This event is fired only if the key combination is supported in the grid.
* Return the target type, target object and the original event. This event is cancelable.
* ```typescript
* changeFocus(event: IGridFocusChangeEventArgs) {
* const changedFocus = event;
* customKeydown(args: IGridKeydownEventArgs) {
* const keydownEvent = args.event;
* }
* ```
* ```html
* * <igx-grid (onFocusChange)="changeFocus($event)"></igx-grid>
* <igx-grid (onGridKeydown)="customKeydown($event)"></igx-grid>
* ```
*/
*/
@Output()
public onFocusChange = new EventEmitter<IFocusChangeEventArgs>();
public onGridKeydown = new EventEmitter<IGridKeydownEventArgs>();

/**
* @hidden
Expand Down Expand Up @@ -4872,6 +4893,113 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
directive.scrollTo(goal);
}

public navigateTo(rowIndex: number, visibleColIndex = -1, cb: Function = null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Public API. Doesn't have description and code snippet.

if (rowIndex < 0 || rowIndex > this.verticalScrollContainer.igxForOf.length - 1
|| (visibleColIndex !== -1 && this.columnList.map(col => col.visibleIndex).indexOf(visibleColIndex) === -1)) {
return;
}
this.wheelHandler();
if (visibleColIndex === -1 || (this.navigation.isColumnFullyVisible(visibleColIndex)
&& this.navigation.isColumnLeftFullyVisible(visibleColIndex))) {
if (this.navigation.shouldPerformVerticalScroll(rowIndex)) {
this.verticalScrollContainer.scrollTo(rowIndex);
this.verticalScrollContainer.onChunkLoad
.pipe(first()).subscribe(() => {
this.executeCallback(rowIndex, visibleColIndex, cb);
});
} else {
this.executeCallback(rowIndex, visibleColIndex, cb);
}
} else {
const unpinnedIndex = this.navigation.getColumnUnpinnedIndex(visibleColIndex);
this.parentVirtDir.onChunkLoad
.pipe(first())
.subscribe(() => {
if (this.navigation.shouldPerformVerticalScroll(rowIndex)) {
this.verticalScrollContainer.scrollTo(rowIndex);
this.verticalScrollContainer.onChunkLoad
.pipe(first()).subscribe(() => {
this.executeCallback(rowIndex, visibleColIndex, cb);
});
} else {
this.executeCallback(rowIndex, visibleColIndex, cb);
}

});
this.navigation.horizontalScroll(rowIndex).scrollTo(unpinnedIndex);
}
}

public getNextCell(currRowIndex, curVisibleColIndex, callback: (IgxColumnComponent) => boolean = null) {
const visibleColIndex = curVisibleColIndex;
const colIndexes = callback ? this.columnList.filter((col) => callback(col)).map(editCol => editCol.visibleIndex) :
this.columnList.map(editCol => editCol.visibleIndex);
const nextCellIndex = colIndexes.find(index => index > visibleColIndex);
if (nextCellIndex !== undefined) {
return {rowIndex: currRowIndex, visibleColumnIndex: nextCellIndex};
} else {
if (this.getNextDataRowIndex(currRowIndex) === currRowIndex) {
return {rowIndex: this.getNextDataRowIndex(currRowIndex), visibleColumnIndex: visibleColIndex};
} else {
return {rowIndex: this.getNextDataRowIndex(currRowIndex), visibleColumnIndex: colIndexes[0]};
}
}
}

public getPreviousCell(currRowIndex, curVisibleColIndex, callback: (IgxColumnComponent) => boolean = null) {
const visibleColIndex = curVisibleColIndex;
const colIndexes = callback ? this.columnList.filter((col) => callback(col)).map(editCol => editCol.visibleIndex) :
this.columnList.map(editCol => editCol.visibleIndex);
const prevCellIndex = colIndexes.reverse().find(index => index < visibleColIndex);
if (prevCellIndex !== undefined) {
return {rowIndex: currRowIndex, visibleColumnIndex: prevCellIndex};
} else {
if (this.getPrevDataRowIndex(currRowIndex) === currRowIndex) {
return {rowIndex: this.getPrevDataRowIndex(currRowIndex), visibleColumnIndex: visibleColIndex};
} else {
return {rowIndex: this.getPrevDataRowIndex(currRowIndex), visibleColumnIndex: colIndexes[0]};
}
}
}

private executeCallback(rowIndex, visibleColIndex = -1, cb: Function = null) {
if (!cb) { return; }
let targetType, target;
const row = this.summariesRowList.filter(s => s.index !== 0).concat(this.rowList.toArray()).find(r => r.index === rowIndex);
if (!row) { return; }
switch (row.nativeElement.tagName.toLowerCase()) {
case 'igx-grid-groupby-row':
targetType = GridKeydownTargetType.groupRow;
target = row;
break;
case 'igx-grid-summary-row':
targetType = GridKeydownTargetType.summaryCell;
target = visibleColIndex !== -1 ?
row.summaryCells.find(c => c.visibleColumnIndex === visibleColIndex) : row.summaryCells.first;
break;
default:
targetType = GridKeydownTargetType.dataCell;
target = visibleColIndex !== -1 ? row.cells.find(c => c.visibleColumnIndex === visibleColIndex) : row.cells.first;
break;
}
const args = { targetType: targetType, target: target };
cb(args);
}

private getPrevDataRowIndex(currentRowIndex): number {
if (currentRowIndex <= 0) { return currentRowIndex; }
const prevRow = this.verticalScrollContainer.igxForOf.slice(0, currentRowIndex).reverse()
.find(rec => !rec.expression && !rec.summaries);
return prevRow ? this.verticalScrollContainer.igxForOf.indexOf(prevRow) : currentRowIndex;
}

private getNextDataRowIndex(currentRowIndex): number {
if (currentRowIndex === this.verticalScrollContainer.igxForOf.length) {return currentRowIndex; }
const nextRow = this.verticalScrollContainer.igxForOf.slice(currentRowIndex + 1, this.verticalScrollContainer.igxForOf.length)
.find(rec => !rec.expression && !rec.summaries);
return nextRow ? this.verticalScrollContainer.igxForOf.indexOf(nextRow) : currentRowIndex;
}

private rebuildMatchCache() {
this.lastSearchInfo.matchInfoCache = [];

Expand Down
Loading