Skip to content

Commit 0a93e08

Browse files
authored
feat(igxHierarchicalGrid): Add api to navigate to a specific child grid. (#15201)
1 parent 37952b8 commit 0a93e08

File tree

6 files changed

+143
-8
lines changed

6 files changed

+143
-8
lines changed

projects/igniteui-angular-elements/src/analyzer/elements.config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ export var registerConfig = [
550550
{ name: "foreignKey" },
551551
{ name: "selectedCells" },
552552
{ name: "gridAPI", writable: true },
553+
{ name: "navigation", writable: true },
553554
{ name: "shouldGenerate", writable: true },
554555
{ name: "rowList" },
555556
{ name: "dataRowList" },
@@ -561,7 +562,6 @@ export var registerConfig = [
561562
{ name: "filteredSortedData" },
562563
{ name: "validation" },
563564
{ name: "cdr" },
564-
{ name: "navigation", writable: true },
565565
{ name: "virtualizationState" },
566566
{ name: "nativeElement" },
567567
{ name: "defaultRowHeight" },
@@ -733,6 +733,7 @@ export var registerConfig = [
733733
],
734734
additionalProperties: [
735735
{ name: "dimensionsSortingExpressions" },
736+
{ name: "navigation", writable: true },
736737
{ name: "allDimensions" },
737738
{ name: "rowList" },
738739
{ name: "dataRowList" },
@@ -742,7 +743,6 @@ export var registerConfig = [
742743
{ name: "validation" },
743744
{ name: "gridAPI" },
744745
{ name: "cdr" },
745-
{ name: "navigation", writable: true },
746746
{ name: "virtualizationState" },
747747
{ name: "nativeElement" },
748748
{ name: "defaultRowHeight" },
@@ -861,13 +861,13 @@ export var registerConfig = [
861861
additionalProperties: [
862862
{ name: "rowIslandAPI", writable: true },
863863
{ name: "gridAPI", writable: true },
864+
{ name: "navigation", writable: true },
864865
{ name: "shouldGenerate", writable: true },
865866
{ name: "rowList" },
866867
{ name: "dataRowList" },
867868
{ name: "transactions" },
868869
{ name: "validation" },
869870
{ name: "cdr" },
870-
{ name: "navigation", writable: true },
871871
{ name: "nativeElement" },
872872
{ name: "defaultRowHeight" },
873873
{ name: "defaultHeaderGroupMinWidth" },

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ export class IgxGridNavigationService {
217217

218218
public performVerticalScrollToCell(rowIndex: number, visibleColIndex = -1, cb?: () => void) {
219219
if (!this.shouldPerformVerticalScroll(rowIndex, visibleColIndex)) {
220+
if (cb) {
221+
cb();
222+
}
220223
return;
221224
}
222225
this.pendingNavigation = true;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ export abstract class IgxHierarchicalGridBaseDirective extends IgxGridBaseDirect
200200
);
201201
}
202202

203+
public override navigation: IgxHierarchicalGridNavigationService;
204+
203205
/**
204206
* @hidden
205207
*/

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

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,55 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
179179
}
180180
}
181181

182+
/**
183+
* Navigates to the specific child grid based on the array of paths leading to it
184+
*
185+
* @param pathToChildGrid Array of IPathSegments that describe the path to the child grid
186+
* each segment is described by the rowKey of the parent row and the rowIslandKey.
187+
*/
188+
public navigateToChildGrid(pathToChildGrid: IPathSegment[], cb?: () => void) {
189+
if (pathToChildGrid.length == 0) {
190+
if (cb) {
191+
cb();
192+
}
193+
return;
194+
}
195+
const pathElem = pathToChildGrid.shift();
196+
const rowKey = pathElem.rowKey;
197+
const rowIndex = this.grid.gridAPI.get_row_index_in_data(rowKey);
198+
if (rowIndex === -1) {
199+
if (cb) {
200+
cb();
201+
}
202+
return;
203+
}
204+
// scroll to row, since it can be out of view
205+
this.performVerticalScrollToCell(rowIndex, -1, () => {
206+
this.grid.cdr.detectChanges();
207+
// next, expand row, if it is collapsed
208+
const row = this.grid.getRowByIndex(rowIndex);
209+
if (!row.expanded) {
210+
row.expanded = true;
211+
// update sizes after expand
212+
this.grid.verticalScrollContainer.recalcUpdateSizes();
213+
this.grid.cdr.detectChanges();
214+
}
215+
216+
const childGrid = this.grid.gridAPI.getChildGrid([pathElem]);
217+
if (!childGrid) {
218+
if (cb) {
219+
cb();
220+
}
221+
return;
222+
}
223+
const positionInfo = this.getElementPosition(childGrid.nativeElement, false);
224+
this.grid.verticalScrollContainer.addScrollTop(positionInfo.offset);
225+
this.grid.verticalScrollContainer.chunkLoad.pipe(first()).subscribe(() => {
226+
childGrid.navigation.navigateToChildGrid(pathToChildGrid, cb);
227+
});
228+
});
229+
}
230+
182231
/**
183232
* Moves navigation to child grid.
184233
*
@@ -270,17 +319,28 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi
270319
const childGrid = this.grid.gridAPI.getChildGrid([pathSegment]);
271320
rowElem = childGrid.tfoot.nativeElement;
272321
}
322+
323+
return this.getElementPosition(rowElem, isNext);
324+
}
325+
326+
protected getElementPosition(element: HTMLElement, isNext: boolean) {
327+
// Special handling for scenarios where there is css transformations applied that affects scale.
328+
// getBoundingClientRect().height returns size after transformations
329+
// element.offsetHeight returns size without any transformations
330+
// get the ratio to figure out if anything has applied transformations
331+
const scaling = element.getBoundingClientRect().height / element.offsetHeight;
332+
273333
const gridBottom = this._getMinBottom(this.grid);
274334
const diffBottom =
275-
rowElem.getBoundingClientRect().bottom - gridBottom;
335+
element.getBoundingClientRect().bottom - gridBottom;
276336
const gridTop = this._getMaxTop(this.grid);
277-
const diffTop = rowElem.getBoundingClientRect().bottom -
278-
rowElem.offsetHeight - gridTop;
337+
const diffTop = element.getBoundingClientRect().bottom -
338+
element.getBoundingClientRect().height - gridTop;
279339
// Adding Math.Round because Chrome has some inconsistencies when the page is zoomed
280340
const isInView = isNext ? Math.round(diffBottom) <= 0 : Math.round(diffTop) >= 0;
281341
const calcOffset = isNext ? diffBottom : diffTop;
282342

283-
return { inView: isInView, offset: calcOffset };
343+
return { inView: isInView, offset: calcOffset / scaling};
284344
}
285345

286346
/**

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

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import { IgxHierarchicalRowComponent } from './hierarchical-row.component';
1010
import { clearGridSubs, setupHierarchicalGridScrollDetection } from '../../test-utils/helper-utils.spec';
1111
import { GridFunctions } from '../../test-utils/grid-functions.spec';
1212
import { IgxGridCellComponent } from '../cell.component';
13-
import { IGridCellEventArgs, IgxColumnComponent } from '../public_api';
13+
import { IGridCellEventArgs, IgxColumnComponent, IPathSegment } from '../public_api';
14+
import { IgxHierarchicalGridNavigationService } from './hierarchical-grid-navigation.service';
1415

1516
const DEBOUNCE_TIME = 50;
1617
const GRID_CONTENT_CLASS = '.igx-grid__tbody-content';
@@ -950,6 +951,73 @@ describe('IgxHierarchicalGrid Navigation', () => {
950951
expect(secondChildCell.active).toBe(true);
951952
});
952953
});
954+
955+
describe('IgxHierarchicalGrid Navigation API #hGrid', () => {
956+
beforeEach(waitForAsync(() => {
957+
fixture = TestBed.createComponent(IgxHierarchicalGridMultiLayoutComponent);
958+
fixture.detectChanges();
959+
hierarchicalGrid = fixture.componentInstance.hgrid;
960+
setupHierarchicalGridScrollDetection(fixture, hierarchicalGrid);
961+
baseHGridContent = GridFunctions.getGridContent(fixture);
962+
GridFunctions.focusFirstCell(fixture, hierarchicalGrid);
963+
}));
964+
965+
afterEach(() => {
966+
clearGridSubs();
967+
});
968+
969+
it('should navigate to exact child grid with navigateToChildGrid.', (done) => {
970+
hierarchicalGrid.primaryKey = 'ID';
971+
hierarchicalGrid.expandChildren = false;
972+
fixture.detectChanges();
973+
const path: IPathSegment = {
974+
rowKey: 10,
975+
rowIslandKey: 'childData2',
976+
rowID: 10
977+
};
978+
hierarchicalGrid.navigation.navigateToChildGrid([path], () => {
979+
fixture.detectChanges();
980+
const childGrid = hierarchicalGrid.gridAPI.getChildGrid([path]).nativeElement;
981+
expect(childGrid).not.toBe(undefined);
982+
983+
const parentBottom = hierarchicalGrid.tbody.nativeElement.getBoundingClientRect().bottom;
984+
const parentTop = hierarchicalGrid.tbody.nativeElement.getBoundingClientRect().top;
985+
// check it's in view within its parent
986+
expect(childGrid.getBoundingClientRect().bottom <= parentBottom && childGrid.getBoundingClientRect().top >= parentTop);
987+
done();
988+
});
989+
});
990+
it('should navigate to exact nested child grid with navigateToChildGrid.', (done) => {
991+
hierarchicalGrid.expandChildren = false;
992+
hierarchicalGrid.primaryKey = 'ID';
993+
hierarchicalGrid.childLayoutList.toArray()[0].primaryKey = 'ID';
994+
fixture.detectChanges();
995+
const targetRoot: IPathSegment = {
996+
rowKey: 10,
997+
rowIslandKey: 'childData',
998+
rowID: 10
999+
};
1000+
const targetNested: IPathSegment = {
1001+
rowKey: 5,
1002+
rowIslandKey: 'childData2',
1003+
rowID: 5
1004+
};
1005+
1006+
hierarchicalGrid.navigation.navigateToChildGrid([targetRoot, targetNested], () => {
1007+
fixture.detectChanges();
1008+
const childGrid = hierarchicalGrid.gridAPI.getChildGrid([targetRoot]).nativeElement;
1009+
expect(childGrid).not.toBe(undefined);
1010+
const childGridNested = hierarchicalGrid.gridAPI.getChildGrid([targetRoot, targetNested]).nativeElement;
1011+
expect(childGridNested).not.toBe(undefined);
1012+
1013+
const parentBottom = childGrid.getBoundingClientRect().bottom;
1014+
const parentTop = childGrid.getBoundingClientRect().top;
1015+
// check it's in view within its parent
1016+
expect(childGridNested.getBoundingClientRect().bottom <= parentBottom && childGridNested.getBoundingClientRect().top >= parentTop);
1017+
done();
1018+
});
1019+
});
1020+
});
9531021
});
9541022

9551023

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,8 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
10561056
_diTransactions);
10571057
}
10581058

1059+
public override navigation: IgxPivotGridNavigationService;
1060+
10591061
/**
10601062
* @hidden
10611063
*/

0 commit comments

Comments
 (0)