diff --git a/projects/igniteui-angular/src/lib/grids/api.service.ts b/projects/igniteui-angular/src/lib/grids/api.service.ts index 1953235f749..09c2cc8cbc1 100644 --- a/projects/igniteui-angular/src/lib/grids/api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/api.service.ts @@ -397,6 +397,13 @@ export class GridBaseAPIService implements GridServiceType { if (args.cancel) { return; } + + const isHierarchicalGrid = grid.nativeElement.tagName.toLowerCase() === 'igx-hierarchical-grid'; + + if (isHierarchicalGrid) { + grid.hgridAPI.endEditAll(); + } + expandedStates.set(rowID, expanded); grid.expansionStates = expandedStates; this.crudService.endEdit(false); diff --git a/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts b/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts index d18a2033404..6c35242174d 100644 --- a/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts +++ b/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts @@ -51,23 +51,23 @@ export interface IGridDataBindable { } export interface CellType { - value: any; - editValue: any; - selected: boolean; - active: boolean; - editable: boolean; - editMode: boolean; + value: any; + editValue: any; + selected: boolean; + active: boolean; + editable: boolean; + editMode: boolean; nativeElement?: HTMLElement; - column: ColumnType; - row: RowType; - grid: GridType; - id: { rowID: any; columnID: number; rowIndex: number }; + column: ColumnType; + row: RowType; + grid: GridType; + id: { rowID: any; columnID: number; rowIndex: number }; cellID?: any; readonly?: boolean; title?: any; - width: string; + width: string; visibleColumnIndex?: number; - update: (value: any) => void; + update: (value: any) => void; setEditMode?(value: boolean): void; calculateSizeToFit?(range: any): number; activate?(event: FocusEvent | KeyboardEvent): void; @@ -96,7 +96,7 @@ export interface RowType { children?: RowType[]; parent?: RowType; hasChildren?: boolean; - treeRow? : ITreeGridRecord; + treeRow?: ITreeGridRecord; addRowUI?: boolean; focused?: boolean; grid: GridType; @@ -246,6 +246,7 @@ export interface GridServiceType { getParentRowId?(child: GridType): any; getChildGrids?(inDepth?: boolean): GridType[]; getChildGrid?(path: IPathSegment[]): GridType; + endEditAll?(): void; // XXX: Fix type unsetChildRowIsland?(rowIsland: any): void; } diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-api.service.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-api.service.ts index b38b8d4f9fd..af7425de844 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-api.service.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-api.service.ts @@ -3,11 +3,10 @@ import { Subject } from 'rxjs'; import { GridType, IPathSegment } from '../common/grid.interface'; import { Injectable } from '@angular/core'; import { GridBaseAPIService } from '../api.service'; - @Injectable() export class IgxHierarchicalGridAPIService extends GridBaseAPIService { protected childRowIslands: Map = new Map(); - protected childGrids: Map> = + protected childGrids: Map> = new Map>(); public registerChildRowIsland(rowIsland: IgxRowIslandComponent) { @@ -127,4 +126,16 @@ export class IgxHierarchicalGridAPIService extends GridBaseAPIService const index = this.get_row_index_in_data(rowID, data); return data[index]; } + + public endEditAll(): void { + const rootGrid = this.grid.rootGrid; + if (rootGrid.gridAPI.crudService.cellInEditMode) { + rootGrid.gridAPI.crudService.endEdit(); + } + rootGrid.hgridAPI.getChildGrids(true).forEach(g => { + if (g.gridAPI.crudService.cellInEditMode) { + g.gridAPI.crudService.endEdit(); + } + }); + } } diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts index 0ea78be32f8..dd048fdc42c 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts @@ -438,6 +438,76 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { expect(childGridSecondRow.inEditMode).toBeFalsy(); }); + it('should be able to prevent exiting of edit mode when row is toggled through the UI', async () => { + hierarchicalGrid.primaryKey = 'ID'; + hierarchicalGrid.rowEditable = true; + hierarchicalGrid.rowToggle.subscribe((e) => { + e.cancel = true; + }); + fixture.detectChanges(); + wait(); + + const masterGridFirstRow = hierarchicalGrid.hgridAPI.get_row_by_index(0) as IgxHierarchicalRowComponent; + expect(masterGridFirstRow.expanded).toBeFalsy(); + + const masterGridSecondCell = masterGridFirstRow.cells.find(c => c.columnIndex === 1); + expect(masterGridSecondCell.editMode).toBeFalsy(); + + masterGridSecondCell.setEditMode(true); + fixture.detectChanges(); + wait(); + + expect(masterGridSecondCell.editMode).toBeTruthy(); + + UIInteractions.simulateClickAndSelectEvent(masterGridFirstRow.expander); + fixture.detectChanges(); + wait(); + + expect(masterGridFirstRow.expanded).toBeFalsy(); + expect(masterGridSecondCell.editMode).toBeTruthy(); + + hierarchicalGrid.rowToggle.subscribe((e) => { + e.cancel = false; + }); + UIInteractions.simulateClickAndSelectEvent(masterGridFirstRow.expander); + fixture.detectChanges(); + wait(); + + expect(masterGridFirstRow.expanded).toBeTruthy(); + expect(masterGridSecondCell.editMode).toBeFalsy(); + + const childGrid = hierarchicalGrid.hgridAPI.getChildGrids(false)[0] as IgxHierarchicalGridComponent; + expect(childGrid).toBeDefined(); + + childGrid.primaryKey = 'ID'; + childGrid.rowEditable = true; + childGrid.rowToggle.subscribe((e) => { + e.cancel = true; + }); + fixture.detectChanges(); + wait(); + + childGrid.columnList.find(c => c.index === 1).editable = true; + const childGridSecondRow = childGrid.gridAPI.get_row_by_index(1) as IgxHierarchicalRowComponent; + expect(childGridSecondRow.expanded).toBeFalsy(); + + const childGridSecondCell = childGridSecondRow.cells.find(c => c.columnIndex === 1); + expect(childGridSecondCell.editMode).toBeFalsy(); + + childGridSecondCell.setEditMode(true); + fixture.detectChanges(); + wait(); + + expect(childGridSecondCell.editMode).toBeTruthy(); + + UIInteractions.simulateClickAndSelectEvent(childGridSecondRow.expander); + fixture.detectChanges(); + wait(); + + expect(childGrid.gridAPI.crudService.cellInEditMode).toBeTruthy(); + expect(childGridSecondRow.inEditMode).toBeTruthy(); + }); + it('child grid width should be recalculated if parent no longer shows scrollbar.', async () => { hierarchicalGrid.height = '1000px'; fixture.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.ts index 19a10cc8373..1eac2933d1b 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.ts @@ -58,7 +58,7 @@ export class IgxHierarchicalRowComponent extends IgxRowDirective { } public get viewIndex(): number { - return this.index + (this.grid.paginator?.page || 0 ) * (this.grid.paginator?.perPage || 0); + return this.index + (this.grid.paginator?.page || 0) * (this.grid.paginator?.perPage || 0); } /** @@ -80,7 +80,7 @@ export class IgxHierarchicalRowComponent extends IgxRowDirective { } public get hasChildren() { - return !!this.grid.childLayoutKeys.length; + return !!this.grid.childLayoutKeys.length; } /** @@ -91,10 +91,10 @@ export class IgxHierarchicalRowComponent extends IgxRowDirective { return this.grid && this.grid.highlightedRowID === this.key; } - /** - * @hidden - */ - public expanderClick(event) { + /** + * @hidden + */ + public expanderClick(event) { event.stopPropagation(); this.toggle(); } @@ -109,7 +109,6 @@ export class IgxHierarchicalRowComponent extends IgxRowDirective { if (this.added) { return; } - this.endEdit(this.grid.rootGrid); this.grid.gridAPI.set_row_expansion_state(this.key, !this.expanded); this.grid.cdr.detectChanges(); } @@ -150,13 +149,6 @@ export class IgxHierarchicalRowComponent extends IgxRowDirective { // TODO: consider moving into CRUD protected endEdit(grid: GridType) { - if (grid.gridAPI.crudService.cellInEditMode) { - grid.gridAPI.crudService.endEdit(); - } - grid.hgridAPI.getChildGrids(true).forEach(g => { - if (g.gridAPI.crudService.cellInEditMode) { - g.gridAPI.crudService.endEdit(); - } - }); + grid.hgridAPI.endEditAll(); } } diff --git a/projects/igniteui-angular/src/public_api.ts b/projects/igniteui-angular/src/public_api.ts index 2c545f5bd1d..348222c0607 100644 --- a/projects/igniteui-angular/src/public_api.ts +++ b/projects/igniteui-angular/src/public_api.ts @@ -136,3 +136,4 @@ export { IChipResourceStrings } from './lib/core/i18n/chip-resources'; export { IActionStripResourceStrings } from './lib/core/i18n/action-strip-resources'; export { PickerInteractionMode } from './lib/date-common/types'; export { SplitterType } from './lib/splitter/splitter.component'; +export { GridSelectionRange } from './lib/grids/common/types';