diff --git a/CHANGELOG.md b/CHANGELOG.md index 405e6164868..00dd45768ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,10 @@ All notable changes for each version of this project will be documented in this - `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid` - Enhanced the advanced filtering to emit the `filtering` event when filters are applied. +### General +- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid` + - The `contextMenu` event now fires when the end-user clicks to the right of the right-most cell in the grid in case the grid's columns don't span its full width. For this reason the event argument of the event is now of type `IGridContextMenuEventArgs` which contains the row object as well as the cell one. The latter will be `null` if the event didn't originate from a cell. **This is not a breaking change** as the new type extends the old. + ## 17.1.0 ### New Features - `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid` diff --git a/projects/igniteui-angular/src/lib/grids/README.md b/projects/igniteui-angular/src/lib/grids/README.md index 2b9e45a2e06..dc154aa5cdc 100644 --- a/projects/igniteui-angular/src/lib/grids/README.md +++ b/projects/igniteui-angular/src/lib/grids/README.md @@ -238,7 +238,7 @@ A list of the events emitted by the **igx-grid**: |`dataPreLoad`| Emitted when a new chunk of data is loaded from virtualization. | |`columnPin`|Emitted when a column is pinned or unpinned through the grid API. The index that the column is inserted at may be changed through the `insertAtIndex` property. Use `isPinned` to check whether the column is pinned or unpinned.| |`columnResized`|Emitted when a column is resized. Returns the column object, previous and new column width.| -|`contextMenu`|Emitted when a cell is right clicked. Returns the cell object.| +|`contextMenu`|Emitted when a cell or row is right clicked. Returns the cell or row object.| |`doubleClick`|Emitted when a cell is double clicked. Returns the cell object.| |`columnVisibilityChanged`| Emitted when `IgxColumnComponent` visibility is changed. Args: { column: any, newValue: boolean } | |`groupingDone`|Emitted when the grouping state changes as a result of grouping columns, ungrouping columns or a combination of both. Provides an array of `ISortingExpression`, an array of the **newly** grouped columns as `IgxColumnComponent` references and an array of the **newly** ungrouped columns as `IgxColumnComponent` references.| diff --git a/projects/igniteui-angular/src/lib/grids/cell.component.ts b/projects/igniteui-angular/src/lib/grids/cell.component.ts index 454061ba0d7..efdbb81a8be 100644 --- a/projects/igniteui-angular/src/lib/grids/cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/cell.component.ts @@ -834,18 +834,6 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy, CellT }); } - /** - * @hidden - * @internal - */ - @HostListener('contextmenu', ['$event']) - public onContextMenu(event: MouseEvent) { - this.grid.contextMenu.emit({ - cell: this.getCellType(), - event - }); - } - /** * @hidden * @internal diff --git a/projects/igniteui-angular/src/lib/grids/common/events.ts b/projects/igniteui-angular/src/lib/grids/common/events.ts index 17788c73c19..85240d9b359 100644 --- a/projects/igniteui-angular/src/lib/grids/common/events.ts +++ b/projects/igniteui-angular/src/lib/grids/common/events.ts @@ -41,6 +41,9 @@ export interface IGridRowEventArgs extends IBaseEventArgs { event: Event; } +/** Represents an event argument for the grid contextMenu output */ +export interface IGridContextMenuEventArgs extends IGridCellEventArgs, IGridRowEventArgs {} + /** Represents event arguments related to grid editing completion. */ export interface IGridEditDoneEventArgs extends IBaseEventArgs { /** 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 dd4e2ee8582..94eb87e4099 100644 --- a/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts +++ b/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts @@ -7,7 +7,8 @@ import { IColumnMovingEventArgs, IPinColumnEventArgs, IActiveNodeChangeEventArgs, ICellPosition, IFilteringEventArgs, IColumnResizeEventArgs, IRowToggleEventArgs, IGridToolbarExportEventArgs, IPinRowEventArgs, - IGridRowEventArgs, IGridEditEventArgs, IRowDataCancelableEventArgs, IGridEditDoneEventArgs + IGridRowEventArgs, IGridEditEventArgs, IRowDataCancelableEventArgs, IGridEditDoneEventArgs, + IGridContextMenuEventArgs } from '../common/events'; import { DisplayDensity, IDensityChangedEventArgs } from '../../core/density'; import { ChangeDetectorRef, ElementRef, EventEmitter, InjectionToken, QueryList, TemplateRef, ViewContainerRef } from '@angular/core'; @@ -1028,7 +1029,7 @@ export interface GridType extends IGridDataBindable { cellClick: EventEmitter; rowClick: EventEmitter; doubleClick: EventEmitter; - contextMenu: EventEmitter; + contextMenu: EventEmitter; selected: EventEmitter; rangeSelected: EventEmitter; rowSelectionChanging: EventEmitter; diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts index 607d6442961..ae10199bb2c 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -121,7 +121,8 @@ import { IGridEditEventArgs, IRowDataCancelableEventArgs, IGridEditDoneEventArgs, - IGridRowEventArgs + IGridRowEventArgs, + IGridContextMenuEventArgs } from './common/events'; import { IgxAdvancedFilteringDialogComponent } from './filtering/advanced-filtering/advanced-filtering-dialog.component'; import { @@ -836,16 +837,16 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements public columnResized = new EventEmitter(); /** - * Emitted when a cell is right clicked. + * Emitted when a cell or row is right clicked. * * @remarks - * Returns the `IgxGridCell` object. + * Returns the `IgxGridCell` object if the immediate context menu target is a cell or an `IgxGridRow` otherwise. * ```html * * ``` */ @Output() - public contextMenu = new EventEmitter(); + public contextMenu = new EventEmitter(); /** * Emitted when a cell is double clicked. diff --git a/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts index 0c979595afa..d516f79824a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts @@ -124,16 +124,15 @@ describe('IgxGrid - Cell component #grid', () => { it('Should trigger contextMenu event when right click into cell', () => { spyOn(grid.contextMenu, 'emit').and.callThrough(); - const event = new Event('contextmenu'); + const event = new Event('contextmenu', { bubbles: true }); cellElem.nativeElement.dispatchEvent(event); - const args: IGridCellEventArgs = { - cell: grid.getCellByColumn(0, 'ID'), - event - }; fix.detectChanges(); expect(grid.contextMenu.emit).toHaveBeenCalledTimes(1); - expect(grid.contextMenu.emit).toHaveBeenCalledWith(args); + expect(grid.contextMenu.emit).toHaveBeenCalledWith(jasmine.objectContaining({ + cell: jasmine.anything(), + row: jasmine.anything() + })); }); it('Should trigger doubleClick event when double click into cell', () => { diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts index dc0216e8c0c..33cec6c02c9 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts @@ -2083,7 +2083,35 @@ describe('IgxGrid Component Tests #grid', () => { fix.detectChanges(); expect(grid.rowClick.emit).toHaveBeenCalledTimes(2); expect(grid.rowClick.emit).toHaveBeenCalledWith(args); - }) + }); + + it('Should emit contextMenu when clicking outside of the columns area', () => { + const fix = TestBed.createComponent(IgxGridDefaultRenderingComponent); + fix.componentInstance.initColumnsRows(5, 5); + //fix.componentInstance.columns.forEach(c => c.width = '100px'); + fix.componentInstance.grid.width = '900px'; + fix.detectChanges(); + const grid = fix.componentInstance.grid; + grid.columnList.forEach(c => c.width = '100px'); + fix.detectChanges(); + const spy = spyOn(grid.contextMenu, 'emit').and.callThrough(); + const event = new Event('contextmenu', { bubbles: true }); + const row = grid.rowList.get(0); + const cell = row.cells.get(0); + cell.nativeElement.dispatchEvent(event); + fix.detectChanges(); + expect(grid.contextMenu.emit).toHaveBeenCalledTimes(1); + expect(grid.contextMenu.emit).toHaveBeenCalledWith(jasmine.objectContaining({ + cell: jasmine.anything() + })); + spy.calls.reset(); + row.nativeElement.dispatchEvent(event); + fix.detectChanges(); + expect(grid.contextMenu.emit).toHaveBeenCalledTimes(1); + expect(grid.contextMenu.emit).toHaveBeenCalledWith(jasmine.objectContaining({ + row: jasmine.anything() + })); + }); it(`Verify that getRowData returns correct data`, () => { const fix = TestBed.createComponent(IgxGridDefaultRenderingComponent); diff --git a/projects/igniteui-angular/src/lib/grids/row.directive.ts b/projects/igniteui-angular/src/lib/grids/row.directive.ts index 5166721fab8..b8fc8613ba2 100644 --- a/projects/igniteui-angular/src/lib/grids/row.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/row.directive.ts @@ -411,6 +411,20 @@ export class IgxRowDirective implements DoCheck, AfterViewInit, OnDestroy { } } + /** + * @hidden + * @internal + */ + @HostListener('contextmenu', ['$event']) + public onContextMenu(event: MouseEvent) { + const cell = (event.target as HTMLElement).closest('.igx-grid__td'); + this.grid.contextMenu.emit({ + row: this, + cell: this.cells.find(c => c.nativeElement === cell), + event + }); + } + /** * @hidden * @internal