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

Refactoring filter cell navigation so that it is handled in the navigation service. Handling special scenarios for hierarchical grid in the hierarchical navigation service. #4267

Merged
merged 22 commits into from
Apr 1, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e6ed866
fix(HierarchicalGrid): Refactoring filter cell navigation so that it …
Mar 8, 2019
2069c97
fix(HierarchicalGrid): Moving handling for sceanrios when child has f…
Mar 11, 2019
801cf17
chore(*): Storing and reusing cols collection.
Mar 11, 2019
232f288
Merge branch '7.2.x' into mkirova/fix-4217
mpavlinov Mar 12, 2019
9b2f44d
chore(*): Applying code review comments.
Mar 12, 2019
819893e
Merge branch 'mkirova/fix-4217' of https://github.com/IgniteUI/ignite…
Mar 12, 2019
63850ee
Merge from 7.2.x
Mar 12, 2019
87ba131
chore(*): Moving checks whether next/prev filter cell exists and maki…
Mar 14, 2019
920a087
chore(*): Using visible index for isColumnLeftFullyVisible/isColumnFu…
Mar 14, 2019
9f41f58
Merge from 7.2.x
Mar 14, 2019
14f8255
Merge from 7.2.x
Mar 21, 2019
ea54720
Merge from 7.2.x
Mar 25, 2019
c9a6930
Merge branch '7.2.x' into mkirova/fix-4217
mpavlinov Mar 26, 2019
0a49c18
Merge branch '7.2.x' into mkirova/fix-4217
mpavlinov Mar 26, 2019
3b0b1ec
Merge branch '7.2.x' into mkirova/fix-4217
mpavlinov Mar 27, 2019
8e0de99
fix(HierarchicalGrid): Additional fix in case next child grid row is …
Mar 27, 2019
02e234b
Merge branch 'mkirova/fix-4217' of https://github.com/IgniteUI/ignite…
Mar 27, 2019
b939adb
Merge branch '7.2.x' into mkirova/fix-4217
mpavlinov Mar 27, 2019
ef225f2
Merge branch '7.2.x' into mkirova/fix-4217
mpavlinov Mar 28, 2019
be06b88
Merge branch '7.2.x' into mkirova/fix-4217
kdinev Mar 29, 2019
120014e
Merge branch '7.2.x' into mkirova/fix-4217
ChronosSF Apr 1, 2019
22d1407
Merge branch '7.2.x' into mkirova/fix-4217
mpavlinov Apr 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,46 +82,17 @@ export class IgxGridFilteringCellComponent implements AfterViewInit, OnInit, DoC

@HostListener('keydown.tab', ['$event'])
public onTabKeyDown(eventArgs) {
const nextIndex = this.filteringService.unpinnedFilterableColumns.indexOf(this.column) + 1;

if (this.isLastElementFocused()) {
if (this.column === this.getLastPinnedFilterableColumn() &&
(!this.isColumnLeftVisible(nextIndex) || !this.isColumnRightVisible(nextIndex))) {
this.filteringService.scrollToFilterCell(this.filteringService.unpinnedFilterableColumns[nextIndex], false);
eventArgs.stopPropagation();
return;
}

if (nextIndex >= this.filteringService.unpinnedFilterableColumns.length) {
if (!this.filteringService.grid.filteredData || this.filteringService.grid.filteredData.length > 0) {
if (this.filteringService.grid.rowList.filter(row => row instanceof IgxGridGroupByRowComponent).length > 0) {
eventArgs.stopPropagation();
return;
}
this.navService.goToFirstCell();
}
eventArgs.preventDefault();
} else if (!this.column.pinned && !this.isColumnRightVisible(nextIndex)) {
eventArgs.preventDefault();
this.filteringService.scrollToFilterCell(this.filteringService.unpinnedFilterableColumns[nextIndex], true);
}
this.filteringService.grid.navigation.navigateNextFilterCell(this.column, eventArgs);
}
eventArgs.stopPropagation();
}

@HostListener('keydown.shift.tab', ['$event'])
public onShiftTabKeyDown(eventArgs) {
if (this.isFirstElementFocused()) {
const prevIndex = this.filteringService.unpinnedFilterableColumns.indexOf(this.column) - 1;

if (prevIndex >= 0 && this.column.visibleIndex > 0 && !this.isColumnLeftVisible(prevIndex) && !this.column.pinned) {
eventArgs.preventDefault();
this.filteringService.scrollToFilterCell(this.filteringService.unpinnedFilterableColumns[prevIndex], false);
} else if (this.column.visibleIndex === 0 ||
(prevIndex < 0 && !this.getFirstPinnedFilterableColumn()) ||
this.column === this.getFirstPinnedFilterableColumn()) {
eventArgs.preventDefault();
}
this.filteringService.grid.navigation.navigatePrevFilterCell(this.column, eventArgs);
}
eventArgs.stopPropagation();
}
Expand Down Expand Up @@ -345,16 +316,6 @@ export class IgxGridFilteringCellComponent implements AfterViewInit, OnInit, DoC
}
}

private getLastPinnedFilterableColumn(): IgxColumnComponent {
const pinnedFilterableColums =
this.filteringService.grid.pinnedColumns.filter(col => !(col instanceof IgxColumnGroupComponent) && col.filterable);
return pinnedFilterableColums[pinnedFilterableColums.length - 1];
}

private getFirstPinnedFilterableColumn(): IgxColumnComponent {
return this.filteringService.grid.pinnedColumns.filter(col => !(col instanceof IgxColumnGroupComponent) && col.filterable)[0];
}

private isColumnRightVisible(columnIndex: number): boolean {
let currentColumnRight = 0;
for (let index = 0; index < this.filteringService.unpinnedColumns.length; index++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2399,7 +2399,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements
protected resolver: ComponentFactoryResolver,
protected differs: IterableDiffers,
protected viewRef: ViewContainerRef,
private navigation: IgxGridNavigationService,
public navigation: IgxGridNavigationService,
public filteringService: IgxFilteringService,
@Inject(IgxOverlayService) protected overlayService: IgxOverlayService,
public summaryService: IgxGridSummaryService,
Expand Down
64 changes: 59 additions & 5 deletions projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Injectable } from '@angular/core';
import { IgxGridBaseComponent } from './grid-base.component';
import { first } from 'rxjs/operators';
import { IgxColumnComponent } from './column.component';
import { IgxColumnComponent, IgxColumnGroupComponent } from './column.component';
import { IgxGridGroupByRowComponent } from './grid/groupby-row.component';

enum MoveDirection {
LEFT = 'left',
Expand Down Expand Up @@ -456,15 +457,68 @@ export class IgxGridNavigationService {
}
}

public moveFocusToFilterCell() {
public moveFocusToFilterCell(toStart?: boolean) {
const columns = this.grid.filteringService.unpinnedFilterableColumns;
if (this.isColumnFullyVisible(columns.length - 1)) {
this.grid.filteringService.focusFilterCellChip(columns[columns.length - 1], false);
const targetIndex = toStart ? 0 : columns.length - 1;
const isVisible = toStart ? this.isColumnLeftFullyVisible(targetIndex) : this.isColumnFullyVisible(targetIndex);
Copy link
Member

Choose a reason for hiding this comment

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

isColumnFullyVisible() takes visible index and index from the unpinnedFilterableColumns collection wouldn't work in some scenarios.

if (isVisible) {
this.grid.filteringService.focusFilterCellChip(columns[targetIndex], false);
} else {
this.grid.filteringService.scrollToFilterCell(columns[columns.length - 1], false);
this.grid.filteringService.scrollToFilterCell(columns[targetIndex], false);
}
}

public navigatePrevFilterCell(column: IgxColumnComponent, eventArgs) {
const cols = this.grid.filteringService.unpinnedFilterableColumns;
const prevFilterableIndex = cols.indexOf(column) - 1;
const prevIndex = cols[prevFilterableIndex].visibleIndex;
Copy link
Member

@skrustev skrustev Mar 13, 2019

Choose a reason for hiding this comment

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

The prevFilterableIndex can become -1 if the index of the column is 0 which will result in error getting visibleIndex straight without a check.

const visibleIndex = column.visibleIndex;

if (prevIndex >= 0 && visibleIndex > 0 && !this.isColumnLeftFullyVisible(prevIndex) && !column.pinned) {
eventArgs.preventDefault();
this.grid.filteringService.scrollToFilterCell(cols[prevIndex], false);
Copy link
Member

@skrustev skrustev Mar 13, 2019

Choose a reason for hiding this comment

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

If visible index is used for the prevIndex, for the unpinned filterable columns collection the index of the column may be different that the visible index.

} else if (column.visibleIndex === 0 ||
(prevIndex < 0 && !this.getFirstPinnedFilterableColumn()) ||
column === this.getFirstPinnedFilterableColumn()) {
eventArgs.preventDefault();
}
}

public navigateNextFilterCell(column: IgxColumnComponent, eventArgs) {
skrustev marked this conversation as resolved.
Show resolved Hide resolved
const cols = this.grid.filteringService.unpinnedFilterableColumns;
const nextIndex = cols.indexOf(column) + 1;
if (column === this.getLastPinnedFilterableColumn() &&
Copy link
Member

Choose a reason for hiding this comment

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

Please format this code

!this.isColumnFullyVisible(nextIndex)) {
this.grid.filteringService.scrollToFilterCell(cols[nextIndex], false);
eventArgs.stopPropagation();
return;
}

if (nextIndex >= this.grid.filteringService.unpinnedFilterableColumns.length) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use the 'cols' variable here.

if (!this.grid.filteringService.grid.filteredData || this.grid.filteringService.grid.filteredData.length > 0) {
if (this.grid.filteringService.grid.rowList.filter(row => row instanceof IgxGridGroupByRowComponent).length > 0) {
eventArgs.stopPropagation();
return;
}
this.goToFirstCell();
}
eventArgs.preventDefault();
} else if (!column.pinned && !this.isColumnFullyVisible(nextIndex)) {
eventArgs.preventDefault();
this.grid.filteringService.scrollToFilterCell(this.grid.filteringService.unpinnedFilterableColumns[nextIndex], true);
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use the 'cols' variable here.

}
}

private getLastPinnedFilterableColumn(): IgxColumnComponent {
const pinnedFilterableColums =
this.grid.pinnedColumns.filter(col => !(col instanceof IgxColumnGroupComponent) && col.filterable);
Copy link
Member

Choose a reason for hiding this comment

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

Columns and column groups have a getter for this check: get columnGroup(): Boolean

return pinnedFilterableColums[pinnedFilterableColums.length - 1];
}

private getFirstPinnedFilterableColumn(): IgxColumnComponent {
return this.grid.pinnedColumns.filter(col => !(col instanceof IgxColumnGroupComponent) && col.filterable)[0];
Copy link
Member

Choose a reason for hiding this comment

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

As above

}

public performShiftTabKey(currentRowEl, rowIndex, visibleColumnIndex, isSummary = false) {
if (visibleColumnIndex === 0) {
if (this.isRowInEditMode(rowIndex)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IgxGridNavigationService } from '../grid-navigation.service';
import { IgxHierarchicalGridComponent } from './hierarchical-grid.component';
import { first } from 'rxjs/operators';
import { IgxColumnComponent, FilterMode } from '../grid';
Copy link
Member

Choose a reason for hiding this comment

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

Wrong import! Either import them from the respective files or explicitly import from the barrel file


export class IgxHierarchicalGridNavigationService extends IgxGridNavigationService {
public grid: IgxHierarchicalGridComponent;
Expand Down Expand Up @@ -227,16 +228,63 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
}

public performTab(currentRowEl, rowIndex, visibleColumnIndex) {
if (!this.grid.rowList.find(row => row.index === rowIndex + 1) && this.grid.parent &&
this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === visibleColumnIndex) {
const isLastColumn = this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === visibleColumnIndex;
const nextIndex = rowIndex + 1;
const virt = this.grid.verticalScrollContainer;
const isNextChild = nextIndex <= virt.igxForOf.length - 1 &&
this.grid.isChildGridRecord(virt.igxForOf[nextIndex]);
if (!this.grid.rowList.find(row => row.index === rowIndex + 1) && this.grid.parent &&
this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === visibleColumnIndex) {
Copy link
Member

Choose a reason for hiding this comment

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

Is that not the same check as line 231?

const childContainer = this.getChildGridRowContainer();
const nextIsSiblingChild = this.grid.parent ? !!childContainer.nextElementSibling : false;
if (nextIsSiblingChild) {
this.focusNextChildDOMElem(childContainer, this.grid.parent);
return;
}
this.navigateDown(currentRowEl, rowIndex, 0);
} else if (isLastColumn && isNextChild) {
const isInView = virt.state.startIndex + virt.state.chunkSize > nextIndex;
if (!isInView) {
this.scrollGrid(this.grid, 'next', () => {
this.focusNextChildDOMElem(currentRowEl, this.grid);
});
} else {
this.focusNextChildDOMElem(currentRowEl, this.grid);
}
} else {
super.performTab(currentRowEl, rowIndex, visibleColumnIndex);
}
}

private focusNextChildDOMElem(currentRowEl, grid) {
const gridElem = currentRowEl.nextElementSibling.querySelector('igx-hierarchical-grid');
const childGridID = gridElem.getAttribute('id');
const childGrid = this.getChildGrid(childGridID, grid);
if (childGrid.allowFiltering && childGrid.filterMode === FilterMode.quickFilter) {
childGrid.navigation.moveFocusToFilterCell(true);
return;
}
this.focusNextChild(currentRowEl.nextElementSibling, 0, grid);
}

public navigatePrevFilterCell(column: IgxColumnComponent, eventArgs) {
if (column.visibleIndex === 0 && this.grid.parent) {
eventArgs.preventDefault();
let targetGrid = this.grid.parent;
const prevSiblingChild = this.getChildGridRowContainer().previousElementSibling;
if (prevSiblingChild) {
const gridElem = prevSiblingChild.querySelectorAll('igx-hierarchical-grid')[0];
targetGrid = this.getChildGrid(gridElem.getAttribute('id'), this.grid.parent);
}
this.focusPrev(targetGrid.unpinnedColumns[targetGrid.unpinnedColumns.length - 1].visibleIndex);
} else {
super.navigatePrevFilterCell(column, eventArgs);
}
}

public performShiftTabKey(currentRowEl, rowIndex, visibleColumnIndex) {
if (visibleColumnIndex === 0 && rowIndex === 0 && this.grid.parent) {
if (this.grid.allowFiltering) {
if (this.grid.allowFiltering && this.grid.filterMode === FilterMode.quickFilter) {
this.moveFocusToFilterCell();
} else {
const prevSiblingChild = this.getChildGridRowContainer().previousElementSibling;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,36 @@ describe('IgxHierarchicalGrid Basic Navigation', () => {
expect(parentCell.focused).toBeTruthy();

}));

it('should move focus to/from filter chip when navigat with Tab/Shift+Tab from parent to child that has filtering. ', (async () => {
const child1 = hierarchicalGrid.hgridAPI.getChildGrids(false)[0];
child1.allowFiltering = true;
fixture.detectChanges();

const horizontalScrDir = hierarchicalGrid.dataRowList.toArray()[0].virtDirRow;
horizontalScrDir.scrollTo(6);
await wait(100);
fixture.detectChanges();

const lastParentCell = hierarchicalGrid.getCellByColumn(0, 'childData2');
lastParentCell.nativeElement.focus();
fixture.detectChanges();

lastParentCell.nativeElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab' }));
await wait(100);
fixture.detectChanges();

const filterItems = fixture.debugElement.queryAll(By.css('.igx-chip__item'));
const firstFilterItem = filterItems[0].nativeElement;
expect(document.activeElement === firstFilterItem).toBeTruthy();

firstFilterItem.closest('.igx-grid__filtering-cell').dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', shiftKey: true }));
await wait(100);
fixture.detectChanges();

expect(lastParentCell.selected).toBeTruthy();
expect(lastParentCell.focused).toBeTruthy();
}));
});


Expand Down
10 changes: 5 additions & 5 deletions src/app/hierarchical-grid/hierarchical-grid.sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ <h4 class="sample-title">Sample One</h4>
<igx-column field="ProductName" hasSummary='true'></igx-column>
</igx-column-group>

<igx-row-island [key]="'childData'" [autoGenerate]="false" [allowFiltering]='true' [rowSelectable]='isRowSelectable' [expandChildren]="firstLevelExpanded" #layout1 >
<igx-row-island [key]="'childData'" [autoGenerate]="false" [allowFiltering]='false' [rowSelectable]='isRowSelectable' [expandChildren]="firstLevelExpanded" #layout1 >
<igx-column field="ID" [hasSummary]='true' [dataType]="'number'"></igx-column>
<igx-column-group header="Information2">
<igx-column field="ChildLevels" [groupable]='true'></igx-column>
<igx-column field="ProductName" [groupable]='true'></igx-column>
</igx-column-group>
<igx-row-island [key]="'childData'" [autoGenerate]="false" [rowSelectable]='isRowSelectable' >
<igx-row-island [key]="'childData'" [autoGenerate]="false" [rowSelectable]='isRowSelectable' [allowFiltering]='true' >
<igx-column field="ID" [hasSummary]='true'></igx-column>
<igx-column-group header="Information3">
<igx-column field="ChildLevels"></igx-column>
Expand Down Expand Up @@ -48,10 +48,10 @@ <h4 class="sample-title">Sample two</h4>
<button igxButton="raised" (click)='toggleFirstIsland()'>Toggle level 1</button>
</div>
<igx-hierarchical-grid [data]="localData" [autoGenerate]="true" [height]="'600px'" [width]="'800px'" #hGrid2>
<igx-row-island [key]="'childData'" [autoGenerate]="true" [rowSelectable]='isRowSelectable' >
<igx-row-island [key]="'childData'" [autoGenerate]="true" [rowSelectable]='isRowSelectable'></igx-row-island>
<igx-row-island [key]="'childData'" [autoGenerate]="true" [rowSelectable]='isRowSelectable' [allowFiltering]='true' >
<igx-row-island [key]="'childData'" [autoGenerate]="true" [rowSelectable]='isRowSelectable' [allowFiltering]='true'></igx-row-island>
</igx-row-island>
<igx-row-island [key]="'childData2'" [autoGenerate]="true"></igx-row-island>
<igx-row-island [key]="'childData2'" [autoGenerate]="true" [allowFiltering]='true'></igx-row-island>
</igx-hierarchical-grid>

</div>