diff --git a/projects/igniteui-angular/src/lib/data-operations/pivot-strategy.ts b/projects/igniteui-angular/src/lib/data-operations/pivot-strategy.ts index 678bd2b47dd..99b1b39a437 100644 --- a/projects/igniteui-angular/src/lib/data-operations/pivot-strategy.ts +++ b/projects/igniteui-angular/src/lib/data-operations/pivot-strategy.ts @@ -101,7 +101,6 @@ export class PivotColumnDimensionsStrategy implements IPivotDimensionStrategy { }) } }); - } this.applyAggregates(rec, columns, values, pivotKeys); } @@ -123,10 +122,6 @@ export class PivotColumnDimensionsStrategy implements IPivotDimensionStrategy { } return leafs; } - - private isLeaf(record, pivotKeys) { - return !(record[pivotKeys.records] && record[pivotKeys.records].some(r => r[pivotKeys.records])); - } } export class DimensionValuesFilteringStrategy extends FilteringStrategy { diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid-keyboard-nav.spec.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid-keyboard-nav.spec.ts index 8ac251eb8b8..c246276d3ad 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid-keyboard-nav.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid-keyboard-nav.spec.ts @@ -52,6 +52,16 @@ describe('IgxPivotGrid - Keyboard navigation #pivotGrid', () => { GridFunctions.verifyHeaderIsFocused(secondCell.parent); activeCells = fixture.debugElement.queryAll(By.css(`${ACTIVE_CELL_CSS_CLASS}`)); expect(activeCells.length).toBe(1); + + // should do nothing if wrong key is pressed + UIInteractions.simulateClickAndSelectEvent(firstCell); + fixture.detectChanges(); + GridFunctions.verifyHeaderIsFocused(firstCell.parent); + activeCells = fixture.debugElement.queryAll(By.css(`${ACTIVE_CELL_CSS_CLASS}`)); + expect(activeCells.length).toBe(1); + UIInteractions.triggerKeyDownEvtUponElem('h', firstCell.nativeElement); + fixture.detectChanges(); + GridFunctions.verifyHeaderIsFocused(firstCell.parent); }); it('should not go outside of the boundaries of the row dimensions content', () => { @@ -119,6 +129,39 @@ describe('IgxPivotGrid - Keyboard navigation #pivotGrid', () => { expect(activeCells.length).toBe(1); }); + it('should allow navigating from any to first row headers(Ctrl + ArrowUp)', () => { + // Ctrl + arrowup + let allGroups = fixture.debugElement.queryAll( + By.directive(IgxPivotRowDimensionHeaderComponent)); + const thirdCell = allGroups.filter(x => x.componentInstance.column.field === 'ProductCategory')[2] + UIInteractions.simulateClickAndSelectEvent(thirdCell); + fixture.detectChanges(); + + UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', thirdCell.nativeElement, true, false, false, true); + fixture.detectChanges(); + + allGroups = fixture.debugElement.queryAll( + By.directive(IgxPivotRowDimensionHeaderComponent)); + const firstCell = allGroups[0]; + GridFunctions.verifyHeaderIsFocused(firstCell.parent); + let activeCells = fixture.debugElement.queryAll(By.css(`${ACTIVE_CELL_CSS_CLASS}`)); + expect(activeCells.length).toBe(1); + + // just arrow up + UIInteractions.simulateClickAndSelectEvent(thirdCell); + fixture.detectChanges(); + + UIInteractions.triggerKeyDownEvtUponElem('ArrowUp', thirdCell.nativeElement, true, false, false, false); + fixture.detectChanges(); + allGroups = fixture.debugElement.queryAll( + By.directive(IgxPivotRowDimensionHeaderComponent)); + const secondCell = allGroups.filter(x => x.componentInstance.column.field === 'ProductCategory')[1]; + GridFunctions.verifyHeaderIsFocused(secondCell.parent); + activeCells = fixture.debugElement.queryAll(By.css(`${ACTIVE_CELL_CSS_CLASS}`)); + expect(activeCells.length).toBe(1); + + }); + it('should allow navigating between column headers', () => { let firstHeader = fixture.debugElement.queryAll( By.css(`${PIVOT_HEADER_ROW} ${HEADER_CELL_CSS_CLASS}`))[0]; @@ -133,7 +176,7 @@ describe('IgxPivotGrid - Keyboard navigation #pivotGrid', () => { UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', pivotGrid.theadRow.nativeElement); fixture.detectChanges(); - + const secondHeader = fixture.debugElement.queryAll( By.css(`${PIVOT_HEADER_ROW} ${HEADER_CELL_CSS_CLASS}`))[1]; GridFunctions.verifyHeaderIsFocused(secondHeader.parent); @@ -191,4 +234,33 @@ describe('IgxPivotGrid - Keyboard navigation #pivotGrid', () => { activeCells = fixture.debugElement.queryAll(By.css(`${ACTIVE_CELL_CSS_CLASS}`)); expect(activeCells.length).toBe(1); }); + + it('should allow navigating within the cells of the body', async () => { + const cell = pivotGrid.rowList.first.cells.first; + GridFunctions.focusFirstCell(fixture, pivotGrid); + fixture.detectChanges(); + expect(pivotGrid.navigation.activeNode.row).toBeUndefined(); + expect(pivotGrid.navigation.activeNode.column).toBeUndefined(); + + UIInteractions.simulateClickAndSelectEvent(cell.nativeElement); + fixture.detectChanges(); + + GridFunctions.focusFirstCell(fixture, pivotGrid); + fixture.detectChanges(); + expect(pivotGrid.navigation.activeNode.row).toBeDefined(); + expect(pivotGrid.navigation.activeNode.column).toBeDefined(); + + let activeCells = fixture.debugElement.queryAll(By.css(`.igx-grid__td--active`)); + expect(activeCells.length).toBe(1); + expect(cell.column.field).toEqual('Stanley-UnitsSold'); + + const gridContent = GridFunctions.getGridContent(fixture); + UIInteractions.triggerEventHandlerKeyDown('arrowright', gridContent); + await wait(30); + fixture.detectChanges(); + + activeCells = fixture.debugElement.queryAll(By.css(`.igx-grid__td--active`)); + expect(activeCells.length).toBe(1); + expect(activeCells[0].componentInstance.column.field).toEqual('Stanley-UnitPrice') + }); }); diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.component.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.component.ts index 4af4c79f82f..9ae24d1930b 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.component.ts @@ -788,7 +788,7 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni } public get selectedRows(): any[] { - if (!this.selectionService.getSelectedRows()) { + if (this.selectionService.getSelectedRows().length === 0) { return []; } const selectedRowIds = []; @@ -2029,13 +2029,6 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni return cols; } - /** - * @hidden @internal - */ - public getPropName(dim: IPivotDimension) { - return !!dim ?? dim.memberName + this.pivotKeys.rowDimensionSeparator + 'height'; - } - /** * @hidden @internal */ diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.spec.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.spec.ts index e6c5074a35b..a06e1cc8c04 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-grid.spec.ts @@ -5,7 +5,7 @@ import { FilteringExpressionsTree, FilteringLogic, IgxPivotGridComponent, IgxPiv import { IgxChipComponent } from '../../chips/chip.component'; import { IgxChipsAreaComponent } from '../../chips/chips-area.component'; import { DefaultPivotSortingStrategy } from '../../data-operations/pivot-sort-strategy'; -import { DimensionValuesFilteringStrategy } from '../../data-operations/pivot-strategy'; +import { DimensionValuesFilteringStrategy, NoopPivotDimensionsStrategy } from '../../data-operations/pivot-strategy'; import { ISortingExpression, SortingDirection } from '../../data-operations/sorting-strategy'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { GridFunctions, GridSelectionFunctions } from '../../test-utils/grid-functions.spec'; @@ -175,17 +175,30 @@ describe('IgxPivotGrid #pivotGrid', () => { it('should remove value from chip', () => { const pivotGrid = fixture.componentInstance.pivotGrid; + pivotGrid.pivotConfiguration.values[1].displayName = 'Units Price'; + pivotGrid.notifyDimensionChange(true); + fixture.detectChanges(); + expect(pivotGrid.columns.length).toBe(9); expect(pivotGrid.values.length).toBe(2); const headerRow = fixture.nativeElement.querySelector('igx-pivot-header-row'); - const rowChip = headerRow.querySelector('igx-chip[id="UnitsSold"]'); - const removeIcon = rowChip.querySelectorAll('igx-icon')[3]; + let rowChip = headerRow.querySelector('igx-chip[id="UnitsSold"]'); + let removeIcon = rowChip.querySelectorAll('igx-icon')[3]; removeIcon.click(); fixture.detectChanges(); expect(pivotGrid.pivotConfiguration.values[0].enabled).toBeFalse(); expect(pivotGrid.values.length).toBe(1); expect(pivotGrid.columns.length).not.toBe(9); + + // should remove the second one as well + rowChip = headerRow.querySelector('igx-chip[id="Units Price"]'); + removeIcon = rowChip.querySelectorAll('igx-icon')[3]; + removeIcon.click(); + fixture.detectChanges(); + expect(pivotGrid.pivotConfiguration.values[1].enabled).toBeFalse(); + expect(pivotGrid.values.length).toBe(0); + expect(pivotGrid.columns.length).toBe(3) }); it('should remove filter dimension from chip', () => { @@ -219,6 +232,53 @@ describe('IgxPivotGrid #pivotGrid', () => { expect(pivotGrid.rowList.length).toBe(5); }); + it('should correctly remove chip from filters dropdown', () => { + const pivotGrid = fixture.componentInstance.pivotGrid; + pivotGrid.pivotConfiguration = { + columns: [], + rows: [ + { + memberName: 'SellerName', + enabled: true + } + ], + filters: [ + { + memberName: 'Date', + enabled: true + }, + { + memberName: 'ProductCategory', + enabled: true + }, + { + memberName: 'Country', + enabled: true + } + ] + }; + pivotGrid.pipeTrigger++; + pivotGrid.setupColumns(); + fixture.detectChanges(); + + const headerRow = fixture.nativeElement.querySelector('igx-pivot-header-row'); + const dropdownIcon = headerRow.querySelector('.igx-grid__tr-pivot--filter').querySelectorAll('igx-icon')[4]; + expect(dropdownIcon).not.toBeUndefined(); + expect(headerRow.querySelector('igx-badge').innerText).toBe('2'); + dropdownIcon.click(); + fixture.detectChanges(); + + const excelMenu = GridFunctions.getExcelStyleFilteringComponents(fixture, 'igx-pivot-grid')[0]; + const chip = excelMenu.querySelectorAll('igx-chip')[0]; + const removeIcon = chip.querySelectorAll('igx-icon')[1]; + removeIcon.click(); + fixture.detectChanges(); + + const filtersChip = headerRow.querySelector('igx-chip[id="Date"]'); + expect(filtersChip).toBeDefined(); + expect(headerRow.querySelector('igx-chip[id="ProductCategory"]')).toBeNull(); + }); + it('should collapse column with 1 value dimension', () => { const pivotGrid = fixture.componentInstance.pivotGrid; pivotGrid.pivotConfiguration.values.pop(); @@ -291,6 +351,21 @@ describe('IgxPivotGrid #pivotGrid', () => { expect(value[1]).toBeFalse(); }); + it('should collapse row', () => { + const pivotGrid = fixture.componentInstance.pivotGrid; + + expect(pivotGrid.rowList.length).toEqual(5); + expect(pivotGrid.expansionStates.size).toEqual(0); + const headerRow = fixture.nativeElement.querySelector('igx-pivot-row-dimension-content'); + const header = headerRow.querySelector('igx-pivot-row-dimension-header'); + const expander = header.querySelectorAll('igx-icon')[0]; + expander.click(); + fixture.detectChanges(); + expect(pivotGrid.rowList.length).toEqual(1); + expect(pivotGrid.expansionStates.size).toEqual(1); + expect(pivotGrid.expansionStates.get('All')).toBeFalse(); + }); + it('should display aggregations when no row dimensions are enabled', () => { const pivotGrid = fixture.componentInstance.pivotGrid; pivotGrid.pivotConfiguration.columns = [ @@ -421,6 +496,91 @@ describe('IgxPivotGrid #pivotGrid', () => { expect(pivotGrid.columnDimensions.length).toEqual(0); }); + it('should change display density', fakeAsync(() => { + const pivotGrid = fixture.componentInstance.pivotGrid; + const minWidthComf = '80'; + const minWidthSupercompact = '56'; + const cellHeightComf = 50; + const cellHeightSuperCompact = 24; + + pivotGrid.superCompactMode = true; + tick(); + fixture.detectChanges(); + + expect(pivotGrid.displayDensity).toBe('compact') + let dimensionContents = fixture.debugElement.queryAll(By.css('.igx-grid__tbody-pivot-dimension')); + let rowHeaders = dimensionContents[0].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(rowHeaders[0].componentInstance.column.minWidth).toBe(minWidthSupercompact); + expect(pivotGrid.rowList.first.cellHeight).toBe(cellHeightSuperCompact); + + pivotGrid.superCompactMode = false; + fixture.detectChanges(); + + pivotGrid.displayDensity = 'comfortable'; + tick(); + fixture.detectChanges(); + + expect(pivotGrid.displayDensity).toBe('comfortable') + rowHeaders = dimensionContents[0].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(rowHeaders[0].componentInstance.column.minWidth).toBe(minWidthComf); + expect(pivotGrid.rowList.first.cellHeight).toBe(cellHeightComf); + })); + + it('should render correct grid with noop strategies', () => { + const pivotGrid = fixture.componentInstance.pivotGrid; + pivotGrid.data = [ + { + AllProducts: 'All Products', All: 2127, 'Bulgaria': 774, 'USA': 829, 'Uruguay': 524, 'AllProducts_records': [ + { ProductCategory: 'Clothing', All: 1523, 'Bulgaria': 774, 'USA': 296, 'Uruguay': 456, }, + { ProductCategory: 'Bikes', All: 68, 'Uruguay': 68 }, + { ProductCategory: 'Accessories', All: 293, 'USA': 293 }, + { ProductCategory: 'Components', All: 240, 'USA': 240 } + ] + } + ]; + + pivotGrid.pivotConfiguration = { + columnStrategy: NoopPivotDimensionsStrategy.instance(), + rowStrategy: NoopPivotDimensionsStrategy.instance(), + columns: [ + { + memberName: 'Country', + enabled: true + }, + ] + , + rows: [ + { + memberFunction: () => 'All', + memberName: 'AllProducts', + enabled: true, + width: '25%', + childLevel: { + memberName: 'ProductCategory', + enabled: true + } + } + ], + values: [ + { + member: 'UnitsSold', + aggregate: { + aggregator: IgxPivotNumericAggregate.sum, + key: 'sum', + label: 'Sum' + }, + enabled: true + }, + ], + filters: null + }; + + pivotGrid.notifyDimensionChange(true); + fixture.detectChanges(); + + expect(pivotGrid.rowList.first.cells.toArray().map(x => x.value)).toEqual([2127, 774, 829, 524]); + }); + describe('IgxPivotGrid Features #pivotGrid', () => { it('should show excel style filtering via dimension chip.', async () => { @@ -811,6 +971,38 @@ describe('IgxPivotGrid #pivotGrid', () => { expect(rowDimensionHeaders).toEqual(expectedHeaders); }); + it('should do nothing on filtering pointer down', () => { + const pivotGrid = fixture.componentInstance.pivotGrid; + pivotGrid.pivotConfiguration.filters = [ + { + memberName: 'Date', + enabled: true + }, + { + memberName: 'ProductCategory', + enabled: true + } + ]; + + pivotGrid.pivotConfiguration.rows = [{ + memberName: 'SellerName', + enabled: true + }]; + pivotGrid.pipeTrigger++; + pivotGrid.setupColumns(); + fixture.detectChanges(); + + const headerRow = fixture.debugElement.queryAll( + By.directive(IgxPivotHeaderRowComponent))[0].componentInstance; + const filtersChip = headerRow.nativeElement.querySelector('igx-chip[id="Date"]'); + expect(filtersChip).not.toBeUndefined(); + const filterIcon = filtersChip.querySelectorAll('igx-icon')[1]; + + spyOn(headerRow, 'onFilteringIconPointerDown').and.callThrough(); + filterIcon.dispatchEvent(new Event('pointerdown')); + expect(headerRow.onFilteringIconPointerDown).toHaveBeenCalledTimes(1); + }); + it('should apply sorting for dimension via row chip', () => { fixture.detectChanges(); const pivotGrid = fixture.componentInstance.pivotGrid; @@ -968,6 +1160,60 @@ describe('IgxPivotGrid #pivotGrid', () => { expect(columnValues).toEqual(expectedOrder); }); + it('should sort date values', () => { + const pivotGrid = fixture.componentInstance.pivotGrid; + pivotGrid.height = '700px'; + pivotGrid.width = '1000px'; + pivotGrid.pivotConfiguration.columns = [ + { + memberName: 'Date', + enabled: true, + dataType: 'date' + } + ]; + pivotGrid.pivotConfiguration.rows = [ + { + memberName: 'AllSeller', + memberFunction: () => 'All Sellers', + enabled: true, + childLevel: { + enabled: true, + memberName: 'SellerName' + } + } + ]; + pivotGrid.notifyDimensionChange(true); + fixture.detectChanges(); + + const headerRow = fixture.nativeElement.querySelector('igx-pivot-header-row'); + const colChip = headerRow.querySelector('igx-chip[id="Date"]'); + + // sort asc + colChip.click(); + fixture.detectChanges(); + + let colHeaders = pivotGrid.columns.filter(x => x.level === 0).map(x => x.header); + let expected = ['01/05/2019', '01/06/2020', '02/19/2020', '05/12/2020', '01/01/2021', '04/07/2021', '12/08/2021'] + expect(colHeaders).toEqual(expected); + + // sort desc + colChip.click(); + fixture.detectChanges(); + + colHeaders = pivotGrid.columns.filter(x => x.level === 0).map(x => x.header); + expected = ['12/08/2021', '04/07/2021', '01/01/2021', '05/12/2020', '02/19/2020', '01/06/2020', '01/05/2019']; + expect(colHeaders).toEqual(expected); + + //remove sort + colChip.click(); + fixture.detectChanges(); + + colHeaders = pivotGrid.columns.filter(x => x.level === 0).map(x => x.header); + expected = ['01/01/2021', '01/05/2019', '01/06/2020', '04/07/2021', '12/08/2021', '05/12/2020', '02/19/2020'] + expect(colHeaders).toEqual(expected); + + }); + it('should allow changing default aggregation via value chip drop-down.', () => { const pivotGrid = fixture.componentInstance.pivotGrid; pivotGrid.width = '1500px'; @@ -1171,6 +1417,13 @@ describe('IgxPivotGrid #pivotGrid', () => { owner: colChip2 }, colChipArea, PivotDimensionType.Column); pivotGrid.cdr.detectChanges(); + + headerRow.onDimDragLeave({ + owner: colChip2 + }); + expect((colChip2.nativeElement.previousElementSibling as any).style.visibility).toBe('hidden'); + expect((colChip2.nativeElement.nextElementSibling as any).style.visibility).toBe('hidden'); + //check chip order is updated. expect(colChipArea.chipsList.toArray()[0].id).toBe(colChip2.id); expect(colChipArea.chipsList.toArray()[1].id).toBe(colChip1.id); @@ -1184,10 +1437,10 @@ describe('IgxPivotGrid #pivotGrid', () => { const pivotGrid = fixture.componentInstance.pivotGrid; fixture.detectChanges(); const headerRow: IgxPivotHeaderRowComponent = fixture.debugElement.query(By.directive(IgxPivotHeaderRowComponent)).componentInstance; - const chipAreas = fixture.debugElement.queryAll(By.directive(IgxChipsAreaComponent)); - const valuesChipArea: IgxChipsAreaComponent = chipAreas[2].componentInstance; - const valChip1 = valuesChipArea.chipsList.toArray()[0]; - const valChip2 = valuesChipArea.chipsList.toArray()[1]; + let chipAreas = fixture.debugElement.queryAll(By.directive(IgxChipsAreaComponent)); + let valuesChipArea: IgxChipsAreaComponent = chipAreas[2].componentInstance; + let valChip1 = valuesChipArea.chipsList.toArray()[0]; + let valChip2 = valuesChipArea.chipsList.toArray()[1]; // move first chip over the second one headerRow.onDimDragOver({ @@ -1211,12 +1464,58 @@ describe('IgxPivotGrid #pivotGrid', () => { owner: valChip2 }, valuesChipArea); pivotGrid.cdr.detectChanges(); + fixture.detectChanges(); + //check chip order is updated. expect(valuesChipArea.chipsList.toArray()[0].id).toBe(valChip2.id); expect(valuesChipArea.chipsList.toArray()[1].id).toBe(valChip1.id); // check dimension order is updated. expect(pivotGrid.pivotConfiguration.values.map(x => x.member)).toEqual(['UnitPrice', 'UnitsSold']); + // should be able to move on the opposite side + chipAreas = fixture.debugElement.queryAll(By.directive(IgxChipsAreaComponent)); + valuesChipArea = chipAreas[2].componentInstance; + valChip1 = valuesChipArea.chipsList.toArray()[0]; + valChip2 = valuesChipArea.chipsList.toArray()[1]; + headerRow.onDimDragOver({ + dragChip: { + id: 'UnitsSold', + data: { pivotArea: 'value' } + }, + owner: valChip1, + originalEvent: { + offsetX: -100 + } + }); + fixture.detectChanges(); + + headerRow.onValueDrop({ + dragChip: valChip2, + owner: valChip1 + }, valuesChipArea); + pivotGrid.cdr.detectChanges(); + fixture.detectChanges(); + //check chip order is updated. + expect(valuesChipArea.chipsList.toArray()[0].id).toBe(valChip2.id); + expect(valuesChipArea.chipsList.toArray()[1].id).toBe(valChip1.id); + // check dimension order is updated. + expect(pivotGrid.pivotConfiguration.values.map(x => x.member)).toEqual(['UnitsSold', 'UnitPrice']); + + //should not be able to drag value to row + headerRow.onDimDragOver({ + dragChip: { + id: 'UnitsSold', + data: { pivotArea: 'value' } + }, + owner: valChip2, + originalEvent: { + offsetX: 100 + } + }, PivotDimensionType.Row); + fixture.detectChanges(); + + expect(pivotGrid.pivotConfiguration.values.map(x => x.member)).toEqual(['UnitsSold', 'UnitPrice']); + expect(pivotGrid.pivotConfiguration.rows.length).toBe(1); }); it('should allow moving dimension between rows, columns and filters.', () => { const pivotGrid = fixture.componentInstance.pivotGrid; @@ -1386,6 +1685,7 @@ describe('IgxPivotGrid #pivotGrid', () => { it('should select/deselect the correct row', () => { fixture.detectChanges(); const pivotGrid = fixture.componentInstance.pivotGrid; + expect(pivotGrid.selectedRows).toEqual([]); const pivotRows = GridFunctions.getPivotRows(fixture); const row = pivotRows[2].componentInstance; const rowHeaders = fixture.debugElement.queryAll( @@ -1576,6 +1876,134 @@ describe('IgxPivotGrid #pivotGrid', () => { expect(rowHeaders[5].componentInstance.column.width).toEqual('200px'); expect(rowHeaders[7].componentInstance.column.width).toEqual('200px'); })); + + it('should update grid after resizing with double click', fakeAsync(() => { + let dimensionContents = fixture.debugElement.queryAll(By.css('.igx-grid__tbody-pivot-dimension')); + + let rowHeaders = dimensionContents[0].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(rowHeaders[0].componentInstance.column.width).toEqual('200px'); + expect(rowHeaders[3].componentInstance.column.width).toEqual('200px'); + + const headerResArea = GridFunctions.getHeaderResizeArea(rowHeaders[3]).nativeElement; + + // Resize first column + UIInteractions.simulateMouseEvent('dblclick', headerResArea, 100, 0); + tick(200); + fixture.detectChanges(); + + rowHeaders = dimensionContents[0].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(parseFloat(rowHeaders[0].componentInstance.column.width)).toBeGreaterThan(200); + expect(parseFloat(rowHeaders[3].componentInstance.column.width)).toBeGreaterThan(200); + + rowHeaders = dimensionContents[1].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(rowHeaders[0].componentInstance.column.width).toEqual('200px'); + expect(rowHeaders[1].componentInstance.column.width).toEqual('200px'); + expect(rowHeaders[5].componentInstance.column.width).toEqual('200px'); + expect(rowHeaders[7].componentInstance.column.width).toEqual('200px'); + })); + + it('should update grid after resizing to equal min width', fakeAsync(() => { + let dimensionContents = fixture.debugElement.queryAll(By.css('.igx-grid__tbody-pivot-dimension')); + + let rowHeaders = dimensionContents[0].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(rowHeaders[0].componentInstance.column.width).toEqual('200px'); + expect(rowHeaders[3].componentInstance.column.width).toEqual('200px'); + + const headerResArea = GridFunctions.getHeaderResizeArea(rowHeaders[3]).nativeElement; + + // Resize first column + UIInteractions.simulateMouseEvent('mousedown', headerResArea, 100, 0); + tick(200); + fixture.detectChanges(); + + const resizer = GridFunctions.getResizer(fixture).nativeElement; + expect(resizer).toBeDefined(); + UIInteractions.simulateMouseEvent('mousemove', resizer, -400, 5); + UIInteractions.simulateMouseEvent('mouseup', resizer, -400, 5); + fixture.detectChanges(); + + rowHeaders = dimensionContents[0].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + const minWdith = parseFloat(rowHeaders[0].componentInstance.column.minWidth); + expect(parseFloat(rowHeaders[0].componentInstance.column.width)).toEqual(minWdith); + expect(parseFloat(rowHeaders[3].componentInstance.column.width)).toEqual(minWdith); + + rowHeaders = dimensionContents[1].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(rowHeaders[0].componentInstance.column.width).toEqual('200px'); + expect(rowHeaders[1].componentInstance.column.width).toEqual('200px'); + expect(rowHeaders[5].componentInstance.column.width).toEqual('200px'); + expect(rowHeaders[7].componentInstance.column.width).toEqual('200px'); + })); + + it('should update grid after resizing with percentages', fakeAsync(() => { + const pivotGrid = fixture.componentInstance.pivotGrid; + pivotGrid.width = '1000px'; + pivotGrid.pivotConfiguration.rows[0].width = '20%'; + pivotGrid.notifyDimensionChange(true); + fixture.detectChanges; + + let dimensionContents = fixture.debugElement.queryAll(By.css('.igx-grid__tbody-pivot-dimension')); + + let rowHeaders = dimensionContents[0].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(parseFloat(rowHeaders[0].componentInstance.column.width)).toBeGreaterThan(150); + expect(parseFloat(rowHeaders[3].componentInstance.column.width)).toBeGreaterThan(150); + expect(pivotGrid.pivotConfiguration.rows[0].width).toEqual('20%'); + + const headerResArea = GridFunctions.getHeaderResizeArea(rowHeaders[3]).nativeElement; + + // Resize first column + UIInteractions.simulateMouseEvent('mousedown', headerResArea, 100, 0); + tick(200); + fixture.detectChanges(); + + const resizer = GridFunctions.getResizer(fixture).nativeElement; + expect(resizer).toBeDefined(); + UIInteractions.simulateMouseEvent('mousemove', resizer, -100, 5); + UIInteractions.simulateMouseEvent('mouseup', resizer, -100, 5); + fixture.detectChanges(); + + rowHeaders = dimensionContents[0].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(parseFloat(rowHeaders[0].componentInstance.column.width)).toBeLessThan(150); + expect(parseFloat(rowHeaders[3].componentInstance.column.width)).toBeLessThan(150); + // less than 10% + expect(parseFloat(pivotGrid.pivotConfiguration.rows[0].width)).toBeLessThan(10); + + + rowHeaders = dimensionContents[1].queryAll(By.directive(IgxPivotRowDimensionHeaderGroupComponent)); + expect(rowHeaders[0].componentInstance.column.width).toEqual('200px'); + })); + + + it('Should not expand columns if collapsed after sorting', () => { + const pivotGrid = fixture.componentInstance.pivotGrid; + pivotGrid.width = '1600px'; + fixture.detectChanges(); + pivotGrid.pivotConfiguration.columns = [ + pivotGrid.pivotConfiguration.rows[1] + ]; + pivotGrid.pivotConfiguration.rows.pop(); + pivotGrid.notifyDimensionChange(true); + fixture.detectChanges(); + + expect(pivotGrid.columns.length).toBe(16); + expect(pivotGrid.rowList.first.cells.length).toBe(8); + + const headerRow = fixture.nativeElement.querySelector('igx-pivot-header-row'); + const header = headerRow.querySelector('igx-grid-header-group'); + const expander = header.querySelectorAll('igx-icon')[0]; + expander.click(); + fixture.detectChanges(); + expect(pivotGrid.columnGroupStates.size).toBe(1); + expect(pivotGrid.rowList.first.cells.length).toBe(2); + + const colChip = headerRow.querySelector('igx-chip[id="AllProducts"]'); + + // sort + colChip.click(); + fixture.detectChanges(); + + expect(pivotGrid.columnGroupStates.size).toBe(1); + expect(pivotGrid.rowList.first.cells.length).toBe(2); + }); }); describe('IgxPivotGrid APIs #pivotGrid', () => { @@ -1601,7 +2029,14 @@ describe('IgxPivotGrid #pivotGrid', () => { pivotGrid = fixture.componentInstance.pivotGrid; })); - it('should allow inserting new dimension at index.', () => { + + it('should allow inserting new dimension.', () => { + //insert wtihout index + pivotGrid.insertDimensionAt({ memberName: 'Date', enabled: true }, PivotDimensionType.Row); + fixture.detectChanges(); + expect(pivotGrid.pivotConfiguration.rows[2].memberName).toBe('Date'); + + // At Index // insert in rows pivotGrid.insertDimensionAt({ memberName: 'SellerName', enabled: true }, PivotDimensionType.Row, 1); fixture.detectChanges(); @@ -1771,8 +2206,8 @@ describe('IgxPivotGrid #pivotGrid', () => { expect(first).toBe('All Cities'); }); - it('should allow inserting new value at index.', () => { - const value = { + it('should allow inserting new value.', () => { + let value = { member: 'Date', aggregate: { aggregator: IgxPivotDateAggregate.latest, @@ -1781,11 +2216,31 @@ describe('IgxPivotGrid #pivotGrid', () => { }, enabled: true }; + // At Index pivotGrid.insertValueAt(value, 1); fixture.detectChanges(); expect(pivotGrid.values.length).toBe(3); expect(pivotGrid.values[1].member).toBe('Date'); expect(pivotGrid.columns.length).toBe(20); + + // With no Index + pivotGrid.pivotConfiguration.values = undefined; + pivotGrid.notifyDimensionChange(true); + fixture.detectChanges(); + pivotGrid.insertValueAt({ + member: 'Date', + displayName: 'DateNew', + aggregate: { + aggregator: IgxPivotDateAggregate.earliest, + key: 'EARLIEST', + label: 'Earliest' + }, + enabled: true + }); + expect(pivotGrid.values.length).toBe(1); + expect(pivotGrid.values[0].member).toBe('Date'); + expect(pivotGrid.values[0].displayName).toBe('DateNew'); + expect(pivotGrid.columns.length).toBe(5); }); it('should allow removing value.', () => { @@ -1816,6 +2271,22 @@ describe('IgxPivotGrid #pivotGrid', () => { it('should allow moving value.', () => { const val = pivotGrid.pivotConfiguration.values[0]; + + //should do nothing if value is not present in the configuration + pivotGrid.moveValue({ + member: 'NotPresent', + enabled:true, + aggregate: { + aggregator: () => {}, + key: 'Test', + label: 'test' + } + }); + fixture.detectChanges(); + expect(pivotGrid.values.length).toBe(2); + expect(pivotGrid.values[0].member).toBe('UnitsSold'); + expect(pivotGrid.values[1].member).toBe('AmountOfSale'); + // move after pivotGrid.moveValue(val, 1); fixture.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.ts index 40d7ca9bf44..c90cf27e4a8 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.ts @@ -310,26 +310,10 @@ export class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent implem public filterRemoved(event: IBaseChipEventArgs) { const filter = this.grid.pivotConfiguration.filters.find(x => x.memberName === event.owner.id); this.grid.toggleDimension(filter); - if (this.isFiltersButton && this.filterDropdownDimensions.has(filter)) { - const selectedChip = this.dropdownChips.chipsList.find(x => x.selected); - if (!selectedChip || selectedChip.id === event.owner.id) { - this.dropdownChips.chipsList.first.selected = true; - } - this.filterDropdownDimensions.delete(filter) - if (this.filterDropdownDimensions.size === 0) { - this.grid.filteringService.hideESF(); - } else { - this.onFiltersAreaDropdownClick({ target: this.filtersButton.el.nativeElement }, undefined, false); - } + if (this.filterDropdownDimensions.size > 0) { + this.onFiltersAreaDropdownClick({ target: this.filtersButton.el.nativeElement }, undefined, false); } else { - if (this.filterAreaDimensions.has(filter)) { - this.filterAreaDimensions.delete(filter) - this.grid.filteringService.hideESF(); - } else if (this.filterDropdownDimensions.size > 0) { - this.onFiltersAreaDropdownClick({ target: this.filtersButton.el.nativeElement }, undefined, false); - } else { - this.grid.filteringService.hideESF(); - } + this.grid.filteringService.hideESF(); } } @@ -359,15 +343,7 @@ export class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent implem event.stopPropagation(); event.preventDefault(); let dim = dimension; - let col; - while (dim) { - col = this.grid.dimensionDataColumns.find(x => x.field === dim.memberName || x.field === dim.member); - if (col) { - break; - } else { - dim = dim.childLevel; - } - } + const col = this.grid.dimensionDataColumns.find(x => x.field === dim.memberName || x.field === dim.member); this.grid.filteringService.toggleFilterDropdown(event.target, col); } @@ -377,15 +353,7 @@ export class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent implem */ public onSummaryClick(eventArgs, value: IPivotValue, dropdown: IgxDropDownComponent, chip: IgxChipComponent) { this._subMenuOverlaySettings.target = eventArgs.currentTarget; - if (dropdown.collapsed) { - this.updateDropDown(value, dropdown, chip); - } else { - // close for previous chip - dropdown.close(); - dropdown.closed.pipe(first()).subscribe(() => { - this.updateDropDown(value, dropdown, chip); - }); - } + this.updateDropDown(value, dropdown, chip); } /** @@ -393,15 +361,7 @@ export class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent implem */ public onFiltersAreaDropdownClick(event, dimension?, shouldReattach = true) { let dim = dimension || this.filterDropdownDimensions.values().next().value; - let col; - while (dim) { - col = this.grid.dimensionDataColumns.find(x => x.field === dim.memberName || x.field === dim.member); - if (col) { - break; - } else { - dim = dim.childLevel; - } - } + const col = this.grid.dimensionDataColumns.find(x => x.field === dim.memberName || x.field === dim.member); if (shouldReattach) { this.dropdownChips.chipsList.forEach(chip => { chip.selected = false @@ -551,12 +511,6 @@ export class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent implem this.onAreaDragLeave(event, area); } - protected getDimensionsType(dimension: IPivotDimension) { - const isColumn = !!this.grid.pivotConfiguration.columns?.find(x => x && x.memberName === dimension.memberName); - const isRow = !!this.grid.pivotConfiguration.rows?.find(x => x && x.memberName === dimension.memberName); - return isColumn ? PivotDimensionType.Column : isRow ? PivotDimensionType.Row : PivotDimensionType.Filter; - } - protected updateDropDown(value: IPivotValue, dropdown: IgxDropDownComponent, chip: IgxChipComponent) { this.value = value; dropdown.width = chip.nativeElement.clientWidth + 'px'; diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-content.component.html b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-content.component.html index 1911b856316..9271eb60afe 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-content.component.html +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-content.component.html @@ -12,7 +12,7 @@ -
+
{{ getExpandState() ? 'expand_more' : 'chevron_right'}} {{column.header}} @@ -21,7 +21,7 @@ -
+
{{column.header}} diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-content.component.ts b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-content.component.ts index cf672b64ac4..b918bbf4da7 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-content.component.ts +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-content.component.ts @@ -131,10 +131,6 @@ export class IgxPivotRowDimensionContentComponent extends IgxGridHeaderRowCompon return this.dimension.level; } - public get rowSpan() { - return this.rowData.rowSpan || 1; - } - protected extractFromDimensions() { const col = this.extractFromDimension(this.dimension, this.rowData); const prevDims = []; diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-header-group.component.html b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-header-group.component.html index 7d409191c6a..6f1a2adc64d 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-header-group.component.html +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-row-dimension-header-group.component.html @@ -1,28 +1,3 @@ - - -
- - - - -
- -
- - {{column.header}} @@ -32,53 +7,6 @@ {{column.expanded ? 'expand_more' : 'chevron_right'}} - - -
- -
- - -
-
- - -
-
- - - - -
- -
- { - if (key.indexOf(pivotKeys.rowDimensionSeparator + pivotKeys.level) !== -1 && - key.indexOf(pivotKeys.level + pivotKeys.rowDimensionSeparator) === -1 && - key.indexOf(pivotKeys.records) === -1) { - total += rec[key] || 0; - } - }); - return total; - } - - public static flattenColumnHierarchy(hierarchies: any, values: IPivotValue[], pivotKeys: IPivotKeys) { - const flatData = []; - hierarchies.forEach((h, key) => { - const obj = {}; - const multipleValues = values.length > 1; - for (const value of values) { - if (h[pivotKeys.aggregations]) { - if (multipleValues) { - obj[key + pivotKeys.columnDimensionSeparator + value.member] = h[pivotKeys.aggregations][value.member]; - } else { - obj[key] = h[pivotKeys.aggregations][value.member]; - } - } - obj[pivotKeys.records] = h[pivotKeys.records]; - flatData.push(obj); - if (h[pivotKeys.children]) { - const records = this.flattenColumnHierarchy(h[pivotKeys.children], values, pivotKeys); - for (const record of records) { - delete record[pivotKeys.records]; - const childKeys = Object.keys(record); - for (const childKey of childKeys) { - obj[childKey] = record[childKey]; - } - } - } - } - }); - - return flatData; - } - public static buildExpressionTree(config: IPivotConfiguration) { const allDimensions = (config.rows || []).concat((config.columns || [])).concat(config.filters || []).filter(x => x !== null && x !== undefined); const enabledDimensions = allDimensions.filter(x => x && x.enabled);