diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss index e5ff370d17f..4615df9e8ca 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss @@ -358,6 +358,10 @@ @extend %igx-grid__td--editing !optional; } + @include e(tr, $m: disabled) { + @extend %igx-grid__tr--disabled !optional; + } + @include e(td, $m: number) { @extend %grid-cell-number !optional; } @@ -392,6 +396,10 @@ @extend %grid-cell--pinned--column-selected !optional; } + @include e(td, $m: pinned-chip) { + @extend %grid-cell--pinned-chip !optional; + } + @include e(td-text) { @extend %grid-cell-text !optional; } @@ -558,6 +566,11 @@ @extend %igx-grid__hierarchical-expander !optional; } + @include e(hierarchical-expander, $m: empty) { + @extend %igx-grid__hierarchical-expander !optional; + @extend %igx-grid__hierarchical-expander--empty !optional; + } + @include e(hierarchical-expander, $m: header) { @extend %igx-grid__hierarchical-expander--header !optional; } @@ -673,6 +686,11 @@ @extend %igx-grid__hierarchical-expander--cosy !optional; } + @include e(hierarchical-expander, $m: empty) { + @extend %igx-grid__hierarchical-expander--cosy !optional; + @extend %igx-grid__hierarchical-expander--empty !optional; + } + @include e(hierarchical-expander, $m: push) { @extend %igx-grid__hierarchical-expander--push--cosy !optional; } @@ -688,6 +706,10 @@ @extend %igx-grid__tree-cell-cosy--padding-level-#{$i} !optional; } } + + @include e(td, $m: pinned-chip) { + @extend %grid-cell--pinned-chip--cosy !optional; + } } @include m(compact) { @@ -772,6 +794,11 @@ @include e(hierarchical-expander) { @extend %igx-grid__hierarchical-expander--compact !optional; } + + @include e(hierarchical-expander, $m: empty) { + @extend %igx-grid__hierarchical-expander--compact !optional; + @extend %igx-grid__hierarchical-expander--empty !optional; + } @include e(hierarchical-expander, $m: push) { @extend %igx-grid__hierarchical-expander--push--compact !optional; @@ -788,6 +815,10 @@ @extend %igx-grid__tree-cell-compact--padding-level-#{$i} !optional; } } + + @include e(td, $m: pinned-chip) { + @extend %grid-cell--pinned-chip--compact !optional; + } } @include _excel-filtering-partial(); diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss index a0368d1a5d4..c19f9a9332b 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss @@ -49,7 +49,8 @@ /// @param {Color} $cell-selected-background [null] - The selected cell background color. /// @param {Color} $cell-selected-text-color [null] - The selected cell text color. /// @param {Color} $cell-editing-background [null] - The background color of the cell being edited. -/// @param {Color} $cell-edited-value-color [null] - The text color of a sell that has been edited. +/// @param {Color} $cell-edited-value-color [null] - The text color of a cell that has been edited. +/// @param {Color} $cell-disabled-color [null] - The text color of a disabled cell. /// /// @param {Color} $edit-mode-color [null] - The color applied around the row when in editing mode. /// @param {Color} $edited-row-indicator [null] - The color applied to the edited row indicator line. @@ -160,6 +161,7 @@ $cell-selected-text-color: null, $cell-editing-background: null, $cell-edited-value-color: null, + $cell-disabled-color: null, $edit-mode-color: null, $edited-row-indicator: null, @@ -505,6 +507,8 @@ edited-row-indicator: $edited-row-indicator, cell-edited-value-color: $cell-edited-value-color, + cell-disabled-color: $cell-disabled-color, + resize-line-color: $resize-line-color, drop-indicator-color: $drop-indicator-color, @@ -1352,6 +1356,12 @@ } } + %igx-grid__tr--disabled { + %grid-cell-text { + color: --var($theme, 'cell-disabled-color'); + } + } + %igx-grid__td--editing { background: --var($theme, 'cell-editing-background') !important; box-shadow: inset 0 0 0 rem(2px) --var($theme, 'edit-mode-color'); @@ -1407,6 +1417,17 @@ } } + %grid-cell--pinned-chip { + margin-#{$right}: rem(12px); + } + + %grid-cell--pinned-chip--cosy { + margin-#{$right}: rem(8px); + } + + %grid-cell--pinned-chip--compact { + margin-#{$right}: rem(4px); + } %grid-cell-header { flex-flow: row nowrap; @@ -2495,6 +2516,11 @@ @include if-rtl() { transform: scaleX(-1); } + + &--empty { + cursor: default; + pointer-events: none; + } } %igx-grid__hierarchical-expander--cosy { diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss index 42b893563e4..c27700764a9 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss @@ -47,6 +47,7 @@ /// @prop {Map} edit-mode-color [igx-color: ('secondary', 500)] - The text color in edit mode. /// @prop {Map} edited-row-indicator [igx-color: ('grays', 400)] - The indicator's color of edited row. /// @prop {Map} cell-edited-value-color [igx-color: ('grays', 600)] - The color of cell edited value. +/// @prop {Map} cell-disabled-color [igx-color: ('grays', 500)] - The text color of a disabled cell. /// @prop {Map} resize-line-color [igx-color: ('secondary', 500)] - The table header resize line color. /// @prop {Map} drop-indicator-color [igx-color: ('secondary', 500)] - The color of the drop indicator. /// @prop {Map} grouparea-background [igx-color: ('grays', 100), hexrgba: #fff] - The grid group area background color. @@ -233,6 +234,10 @@ $_light-grid: extend( igx-color: ('grays', 600) ), + cell-disabled-color: ( + igx-color: ('grays', 500) + ), + resize-line-color: ( igx-color: ('secondary', 500) ), diff --git a/projects/igniteui-angular/src/lib/grids/cell.component.html b/projects/igniteui-angular/src/lib/grids/cell.component.html index df54677f7f9..8832cb84321 100644 --- a/projects/igniteui-angular/src/lib/grids/cell.component.html +++ b/projects/igniteui-angular/src/lib/grids/cell.component.html @@ -1,4 +1,5 @@ + Pinned
row.rowData); + } + /** * Get current selection state. * @example @@ -5344,8 +5355,8 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements columnsArray.forEach((col) => { if (col) { const key = headers ? col.header || col.field : col.field; - record[key] = formatters && col.formatter ? col.formatter(source[row][col.field]) - : source[row][col.field]; + const value = source[row].ghostRecord ? source[row].recordRef[col.field] : source[row][col.field]; + record[key] = formatters && col.formatter ? col.formatter(value) : value; } }); } @@ -5380,7 +5391,7 @@ export class IgxGridBaseDirective extends DisplayDensityBase implements * If `headers` is enabled, it will use the column header (if any) instead of the column field. */ public getSelectedData(formatters = false, headers = false) { - const source = this.dataView; + const source = this.isRowPinningToTop ? [...this.pinnedDataView, ...this.dataView] : [...this.dataView, ...this.pinnedDataView]; return this.extractDataFromSelection(source, formatters, headers); } diff --git a/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts b/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts index fd77fb6be9a..add01e722fe 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts @@ -102,8 +102,8 @@ export class IgxGridNavigationService { break; case 'enter': case 'f2': - if (!this.isDataRow(rowIndex)) { break; } const cell = this.grid.getCellByColumnVisibleIndex(this.activeNode.row, this.activeNode.column); + if (!this.isDataRow(rowIndex) || !cell.editable) { break; } this.grid.crudService.enterEditMode(cell); break; case 'escape': @@ -114,8 +114,8 @@ export class IgxGridNavigationService { case ' ': case 'spacebar': case 'space': - if (this.grid.isRowSelectable && this.isDataRow(rowIndex)) { - const rowObj = this.grid.getRowByIndex(this.activeNode.row); + const rowObj = this.grid.getRowByIndex(this.activeNode.row); + if (this.grid.isRowSelectable && this.isDataRow(rowIndex) && !rowObj.disabled) { rowObj && rowObj.selected ? this.grid.selectionService.deselectRow(rowObj.rowID, event) : this.grid.selectionService.selectRowById(rowObj.rowID, false, event); } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row.component.html b/projects/igniteui-angular/src/lib/grids/grid/grid-row.component.html index 344995caf6c..506e3fd216b 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row.component.html +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row.component.html @@ -77,7 +77,7 @@ [tabindex]="-1" [checked]="selected" [readonly]="true" - [disabled]="deleted" + [disabled]="disabled || deleted" disableRipple="true" [disableTransitions]="grid.disableTransitions" [aria-label]="rowCheckboxAriaLabel"> diff --git a/projects/igniteui-angular/src/lib/grids/grid/row-pinning.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/row-pinning.spec.ts index 567471b3cda..236487f77bd 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/row-pinning.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/row-pinning.spec.ts @@ -15,6 +15,7 @@ import { IgxGridTransaction } from '../tree-grid'; import { IgxTransactionService } from '../../services'; import { GridSummaryFunctions } from '../../test-utils/grid-functions.spec'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; +import { IgxPaginatorComponent } from '../../paginator/paginator.component'; describe('Row Pinning #grid', () => { const FIXED_ROW_CONTAINER = '.igx-grid__tr--pinned '; @@ -401,19 +402,32 @@ describe('Row Pinning #grid', () => { grid.paging = true; grid.perPage = 5; fix.detectChanges(); - let row = grid.getRowByIndex(1); - row.pin(); + const paginator = fix.debugElement.query(By.directive(IgxPaginatorComponent)); + expect(paginator.componentInstance.totalPages).toEqual(6); + + grid.getRowByIndex(1).pin(); fix.detectChanges(); expect(grid.pinnedRows.length).toBe(1); let pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); expect(pinRowContainer.length).toBe(1); - expect(grid.dataView.length).toBe(4); + expect(paginator.componentInstance.totalPages).toEqual(6); + + grid.getRowByIndex(3).pin(); + fix.detectChanges(); + + expect(grid.pinnedRows.length).toBe(2); + pinRowContainer = fix.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); + expect(pinRowContainer.length).toBe(1); + expect(grid.dataView.length).toBe(3); + expect(paginator.componentInstance.totalPages).toEqual(5); // unpin - row = grid.getRowByIndex(0); - row.unpin(); + grid.getRowByIndex(0).unpin(); + fix.detectChanges(); + + grid.getRowByIndex(0).unpin(); fix.detectChanges(); expect(grid.pinnedRows.length).toBe(0); @@ -421,6 +435,7 @@ describe('Row Pinning #grid', () => { expect(pinRowContainer.length).toBe(0); expect(grid.dataView.length).toBe(5); + expect(paginator.componentInstance.totalPages).toEqual(6); }); it('should apply sorting to both pinned and unpinned rows.', () => { diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-cell.component.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-cell.component.ts index 4056b59619d..da8fa856053 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-cell.component.ts @@ -1,7 +1,7 @@ import { IgxGridCellComponent } from '../cell.component'; import { GridBaseAPIService } from '../api.service'; import { ChangeDetectorRef, ElementRef, ChangeDetectionStrategy, Component, - OnInit, HostListener, NgZone } from '@angular/core'; + OnInit, HostListener, NgZone, HostBinding } from '@angular/core'; import { IgxHierarchicalGridComponent } from './hierarchical-grid.component'; import { IgxGridSelectionService, IgxGridCRUDService } from '../selection/selection.service'; import { HammerGesturesManager } from '../../core/touch'; @@ -11,11 +11,10 @@ import { PlatformUtil } from '../../core/utils'; changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, selector: 'igx-hierarchical-grid-cell', - templateUrl: './../cell.component.html', + templateUrl: '../cell.component.html', providers: [HammerGesturesManager] }) export class IgxHierarchicalGridCellComponent extends IgxGridCellComponent implements OnInit { - // protected hSelection; protected _rootGrid; diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html index 2c45fcf2c0a..2023112a766 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.html @@ -86,44 +86,67 @@
+ [style.height.px]='totalHeight' [style.width.px]='calcWidth' #tbody (scroll)='scrollHandler($event)'> - +
+ + + + +
+ +
+ + + - - - - - -
- - -
-
+ [igxTemplateOutlet]='(isHierarchicalRecord(rowData) ? hierarchical_record_template : (isChildGridRecord(rowData) && isExpanded(rowData) ? child_record_template : hierarchical_record_template))' + [igxTemplateOutletContext]='getContext(rowData, rowIndex, false)' (onViewCreated)='viewCreatedHandler($event)' + (onViewMoved)='viewMovedHandler($event)' (onCachedViewLoaded)='cachedViewLoaded($event)'> +
+ + + + + +
+ + +
+
+ + @@ -131,9 +154,12 @@
-
- +
+
+
+ +
+
diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts index ee2b8676058..d15aae8c9ff 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts @@ -111,6 +111,18 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti return this._data; } + /** + * Gets an array of the pinned `IgxRowComponent`s. + * @example + * ```typescript + * const pinnedRow = this.grid.pinnedRows; + * ``` + * @memberof IgxHierarchicalGridComponent + */ + get pinnedRows() { + return this.rowList.filter(x => x.pinned && !x.disabled); + } + /** * @hidden * @deprecated @@ -494,6 +506,9 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti * @hidden */ public isHierarchicalRecord(record: any): boolean { + if (this.isGhostRecord(record)) { + record = record.recordRef; + } return this.childLayoutList.length !== 0 && record[this.childLayoutList.first.key]; } @@ -505,6 +520,10 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti return record.childGridsData !== undefined; } + public isGhostRecord(record: any): boolean { + return record.ghostRecord !== undefined; + } + /** * @hidden */ @@ -519,7 +538,7 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti /** * @hidden */ - public getContext(rowData): any { + public getContext(rowData, rowIndex, pinned): any { if (this.isChildGridRecord(rowData)) { const cachedData = this.childGridTemplates.get(rowData.rowID); if (cachedData) { @@ -542,13 +561,26 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseDirecti } } else { return { - $implicit: rowData, + $implicit: this.isGhostRecord(rowData) ? rowData.recordRef : rowData, templateID: 'dataRow', - index: this.dataView.indexOf(rowData) + index: this.getRowIndex(rowIndex, pinned), + disabled: this.isGhostRecord(rowData) }; } } + /** + * @hidden + */ + public getRowIndex(rowIndex, pinned) { + if (pinned && !this.isRowPinningToTop) { + rowIndex = rowIndex + this.dataView.length; + } else if (!pinned && this.isRowPinningToTop) { + rowIndex = rowIndex + this.pinnedRecordsCount; + } + return rowIndex; + } + /** * @hidden */ diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts index 13143d758a4..ab390416188 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts @@ -1,5 +1,5 @@ import { configureTestSuite } from '../../test-utils/configure-suite'; -import { async, TestBed, tick, fakeAsync } from '@angular/core/testing'; +import { async, TestBed, tick, fakeAsync, ComponentFixture } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { IgxHierarchicalGridModule } from './index'; @@ -13,7 +13,6 @@ import { IgxChildGridRowComponent } from './child-grid-row.component'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; import { take } from 'rxjs/operators'; import { IgxIconModule } from '../../icon'; -import { GridSelectionMode } from '../common/enums'; import { IgxHierarchicalGridTestBaseComponent, IgxHierarchicalGridTestCustomToolbarComponent @@ -21,11 +20,13 @@ import { import { GridFunctions, GridSelectionFunctions } from '../../test-utils/grid-functions.spec'; import { IgxGridToolbarComponent } from '../toolbar/grid-toolbar.component'; import { HierarchicalGridFunctions } from '../../test-utils/hierarchical-grid-functions.spec'; +import { GridSelectionMode, ColumnPinningPosition, RowPinningPosition } from '../common/enums'; +import { IgxPaginatorComponent } from '../../paginator/paginator.component'; import { SampleTestData } from '../../test-utils/sample-test-data.spec'; describe('IgxHierarchicalGrid Integration #hGrid', () => { configureTestSuite(); - let fixture; + let fixture: ComponentFixture; let hierarchicalGrid: IgxHierarchicalGridComponent; const DEBOUNCE_TIME = 30; @@ -169,7 +170,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { fixture.detectChanges(); hierarchicalGrid.addRow({ ID: -1, ProductName: 'Name1' }); fixture.detectChanges(); - const rows = fixture.debugElement.queryAll(By.directive(IgxHierarchicalRowComponent)); + const rows = HierarchicalGridFunctions.getHierarchicalRows(fixture); const lastRow = rows[rows.length - 1]; expect(lastRow.query(By.css('igx-icon')).nativeElement).toHaveClass('igx-icon--inactive'); hierarchicalGrid.transactions.commit(hierarchicalGrid.data); @@ -757,4 +758,237 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { expect(leftMostRightPinnedCellsPart + Number.parseInt(pinnedCellWidth, 10)).toBeLessThan(rightMostGridPart); })); }); + + describe('Row Pinning', () => { + const FIXED_ROW_CONTAINER = '.igx-grid__tr--pinned'; + const FIXED_ROW_CONTAINER_TOP = 'igx-grid__tr--pinned-top'; + const FIXED_ROW_CONTAINER_BOTTOM = 'igx-grid__tr--pinned-bottom'; + beforeEach(() => { + hierarchicalGrid.width = '800px'; + hierarchicalGrid.height = '500px'; + fixture.detectChanges(); + }); + + it('should pin rows to top ', (() => { + hierarchicalGrid.pinRow('0'); + fixture.detectChanges(); + + expect(hierarchicalGrid.pinnedRows.length).toBe(1); + let pinRowContainer = fixture.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); + expect(pinRowContainer.length).toBe(1); + expect(pinRowContainer[0].nativeElement.classList.contains(FIXED_ROW_CONTAINER_TOP)).toBeTruthy(); + expect(pinRowContainer[0].nativeElement.classList.contains(FIXED_ROW_CONTAINER_BOTTOM)).toBeFalsy(); + + expect(pinRowContainer[0].children[0].context.rowID).toBe('0'); + expect(hierarchicalGrid.getRowByIndex(1).rowID).toBe('0'); + expect(hierarchicalGrid.getRowByIndex(2).rowID).toBe('1'); + expect(hierarchicalGrid.getRowByIndex(3).rowID).toBe('2'); + + hierarchicalGrid.pinRow('2'); + fixture.detectChanges(); + + pinRowContainer = fixture.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); + expect(pinRowContainer[0].children.length).toBe(2); + + expect(pinRowContainer[0].children[0].context.rowID).toBe('0'); + expect(pinRowContainer[0].children[1].context.rowID).toBe('2'); + expect(hierarchicalGrid.getRowByIndex(2).rowID).toBe('0'); + expect(hierarchicalGrid.getRowByIndex(3).rowID).toBe('1'); + expect(hierarchicalGrid.getRowByIndex(4).rowID).toBe('2'); + + expect(hierarchicalGrid.pinnedRowHeight).toBe(2 * hierarchicalGrid.renderedRowHeight + 2); + const expectedHeight = parseInt(hierarchicalGrid.height, 10) - + hierarchicalGrid.pinnedRowHeight - 18 - hierarchicalGrid.theadRow.nativeElement.offsetHeight; + expect(hierarchicalGrid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + })); + + it('should pin rows to bottom', (() => { + fixture.componentInstance.pinningConfig = { columns: ColumnPinningPosition.Start, rows: RowPinningPosition.Bottom }; + fixture.detectChanges(); + + // Pin 2nd row + hierarchicalGrid.pinRow('1'); + fixture.detectChanges(); + + expect(hierarchicalGrid.pinnedRows.length).toBe(1); + let pinRowContainer = fixture.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); + expect(pinRowContainer.length).toBe(1); + expect(pinRowContainer[0].nativeElement.classList.contains(FIXED_ROW_CONTAINER_TOP)).toBeFalsy(); + expect(pinRowContainer[0].nativeElement.classList.contains(FIXED_ROW_CONTAINER_BOTTOM)).toBeTruthy(); + + expect(pinRowContainer[0].children.length).toBe(1); + expect(pinRowContainer[0].children[0].context.rowID).toBe('1'); + expect(pinRowContainer[0].children[0].context.index).toBe(fixture.componentInstance.data.length); + expect(pinRowContainer[0].children[0].nativeElement) + .toBe(hierarchicalGrid.getRowByIndex(fixture.componentInstance.data.length).nativeElement); + + expect(hierarchicalGrid.getRowByIndex(0).rowID).toBe('0'); + expect(hierarchicalGrid.getRowByIndex(1).rowID).toBe('1'); + expect(hierarchicalGrid.getRowByIndex(2).rowID).toBe('2'); + + // Pin 1st row + hierarchicalGrid.pinRow('0'); + fixture.detectChanges(); + + pinRowContainer = fixture.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); + expect(pinRowContainer[0].children.length).toBe(2); + expect(pinRowContainer[0].children[0].context.rowID).toBe('0'); + expect(pinRowContainer[0].children[1].context.rowID).toBe('1'); + expect(hierarchicalGrid.getRowByIndex(0).rowID).toBe('0'); + expect(hierarchicalGrid.getRowByIndex(1).rowID).toBe('1'); + expect(hierarchicalGrid.getRowByIndex(2).rowID).toBe('2'); + + // Check last pinned is fully in view + const last = pinRowContainer[0].children[1].context.nativeElement; + expect(last.getBoundingClientRect().bottom - hierarchicalGrid.tbody.nativeElement.getBoundingClientRect().bottom).toBe(0); + + // 2 records pinned + 2px border + expect(hierarchicalGrid.pinnedRowHeight).toBe(2 * hierarchicalGrid.renderedRowHeight + 2); + const expectedHeight = parseInt(hierarchicalGrid.height, 10) - + hierarchicalGrid.pinnedRowHeight - 18 - hierarchicalGrid.theadRow.nativeElement.offsetHeight; + expect(hierarchicalGrid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + })); + + xit('should search in both pinned and unpinned rows.', () => { + let findCount = hierarchicalGrid.findNext('Product: A0'); + fixture.detectChanges(); + + let spans = fixture.debugElement.queryAll(By.css('.igx-highlight')); + expect(spans.length).toBe(1); + expect(findCount).toEqual(1); + + // Pin 3rd row + hierarchicalGrid.pinRow('2'); + fixture.detectChanges(); + expect(hierarchicalGrid.pinnedRows.length).toBe(2); + + findCount = hierarchicalGrid.findNext('Product: A0'); + fixture.detectChanges(); + + spans = fixture.debugElement.queryAll(By.css('.igx-highlight')); + expect(spans.length).toBe(2); + expect(findCount).toEqual(2); + }); + + it('should apply filtering to both pinned and unpinned rows.', () => { + hierarchicalGrid.pinRow('1'); + fixture.detectChanges(); + hierarchicalGrid.pinRow('5'); + fixture.detectChanges(); + + let pinRowContainer = fixture.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); + expect(pinRowContainer[0].children.length).toBe(2); + expect(pinRowContainer[0].children[0].context.rowID).toBe('1'); + expect(pinRowContainer[0].children[1].context.rowID).toBe('5'); + + hierarchicalGrid.filter('ID', '5', IgxStringFilteringOperand.instance().condition('contains'), false); + fixture.detectChanges(); + + const allRows = HierarchicalGridFunctions.getHierarchicalRows(fixture); + pinRowContainer = fixture.debugElement.queryAll(By.css(FIXED_ROW_CONTAINER)); + expect(pinRowContainer[0].children.length).toBe(1); + expect(pinRowContainer[0].children[0].context.rowID).toBe('5'); + expect(allRows[1].componentInstance.rowID).toEqual('5'); + }); + + it('should render paging with correct data and rows be correctly paged.', () => { + hierarchicalGrid.paging = true; + hierarchicalGrid.perPage = 5; + hierarchicalGrid.height = '700px'; + fixture.detectChanges(); + + let rows = HierarchicalGridFunctions.getHierarchicalRows(fixture); + const paginator = fixture.debugElement.query(By.directive(IgxPaginatorComponent)); + expect(rows.length).toEqual(5); + expect(paginator.componentInstance.perPage).toEqual(5); + expect(paginator.componentInstance.totalPages).toEqual(8); + + hierarchicalGrid.pinRow('1'); + fixture.detectChanges(); + + rows = HierarchicalGridFunctions.getHierarchicalRows(fixture); + expect(rows.length).toEqual(6); + expect(paginator.componentInstance.perPage).toEqual(5); + expect(paginator.componentInstance.totalPages).toEqual(8); + + hierarchicalGrid.pinRow('3'); + fixture.detectChanges(); + + rows = HierarchicalGridFunctions.getHierarchicalRows(fixture); + expect(rows.length).toEqual(7); + expect(paginator.componentInstance.perPage).toEqual(5); + expect(paginator.componentInstance.totalPages).toEqual(8); + }); + + it('should apply sorting to both pinned and unpinned rows.', () => { + hierarchicalGrid.pinRow('1'); + hierarchicalGrid.pinRow('3'); + fixture.detectChanges(); + + expect(hierarchicalGrid.getRowByIndex(0).rowID).toBe('1'); + expect(hierarchicalGrid.getRowByIndex(1).rowID).toBe('3'); + + hierarchicalGrid.sort({ fieldName: 'ID', dir: SortingDirection.Desc, ignoreCase: false }); + fixture.detectChanges(); + + // check pinned rows data is sorted + expect(hierarchicalGrid.getRowByIndex(0).rowID).toBe('3'); + expect(hierarchicalGrid.getRowByIndex(1).rowID).toBe('1'); + + // check unpinned rows data is sorted + const lastIndex = fixture.componentInstance.data.length - 1; + // Expect 9 since it is a string. + expect(hierarchicalGrid.getRowByIndex(2).rowID).toBe('9'); + }); + + it('should return pinned rows as well on multiple cell selection in both pinned and unpinned areas', async() => { + hierarchicalGrid.pinRow('1'); + fixture.detectChanges(); + + let range = { rowStart: 0, rowEnd: 2, columnStart: 'ID', columnEnd: 'ChildLevels' }; + hierarchicalGrid.selectRange(range); + fixture.detectChanges(); + + let selectedData = hierarchicalGrid.getSelectedData(); + expect(selectedData).toEqual([{ID: '1', ChildLevels: 3}, {ID: '0', ChildLevels: 3}, {ID: '1', ChildLevels: 3}]); + + fixture.componentInstance.pinningConfig = { columns: ColumnPinningPosition.Start, rows: RowPinningPosition.Bottom }; + fixture.detectChanges(); + + hierarchicalGrid.verticalScrollContainer.getScroll().scrollTop = 5000; + await wait(); + + range = { rowStart: 38, rowEnd: 40, columnStart: 'ID', columnEnd: 'ChildLevels' }; + hierarchicalGrid.clearCellSelection(); + hierarchicalGrid.selectRange(range); + fixture.detectChanges(); + + selectedData = hierarchicalGrid.getSelectedData(); + expect(selectedData).toEqual([{ID: '38', ChildLevels: 3}, {ID: '39', ChildLevels: 3}, {ID: '1', ChildLevels: 3}]); + }); + + it('should return correct filterData collection after filtering.', () => { + hierarchicalGrid.pinRow('1'); + hierarchicalGrid.pinRow('11'); + fixture.detectChanges(); + + hierarchicalGrid.filter('ID', '1', IgxStringFilteringOperand.instance().condition('contains'), false); + fixture.detectChanges(); + + let gridFilterData = hierarchicalGrid.filteredData; + expect(gridFilterData.length).toBe(15); + expect(gridFilterData[0].ID).toBe('1'); + expect(gridFilterData[1].ID).toBe('11'); + expect(gridFilterData[2].ID).toBe('1'); + + fixture.componentInstance.pinningConfig = { columns: ColumnPinningPosition.Start, rows: RowPinningPosition.Bottom }; + fixture.detectChanges(); + + gridFilterData = hierarchicalGrid.filteredData; + expect(gridFilterData.length).toBe(15); + expect(gridFilterData[0].ID).toBe('1'); + expect(gridFilterData[1].ID).toBe('11'); + expect(gridFilterData[2].ID).toBe('1'); + }); + }); }); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts index a445d485ec2..ba6f296d18f 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts @@ -2,7 +2,7 @@ import { NgModule } from '@angular/core'; import { IgxGridModule } from '../grid/grid.module'; import { IgxHierarchicalGridComponent } from './hierarchical-grid.component'; import { IgxHierarchicalRowComponent } from './hierarchical-row.component'; -import { IgxGridHierarchicalPipe, IgxGridHierarchicalPagingPipe } from './hierarchical-grid.pipes'; +import { IgxGridHierarchicalPipe, IgxGridHierarchicalPagingPipe, IgxGridHierarchicalRowPinning } from './hierarchical-grid.pipes'; import { IgxRowIslandComponent } from './row-island.component'; import { IgxChildGridRowComponent } from './child-grid-row.component'; import { IgxHierarchicalGridCellComponent } from './hierarchical-cell.component'; @@ -21,7 +21,8 @@ import { IgxHierarchicalGridBaseDirective } from './hierarchical-grid-base.direc IgxChildGridRowComponent, IgxHierarchicalGridCellComponent, IgxGridHierarchicalPipe, - IgxGridHierarchicalPagingPipe + IgxGridHierarchicalPagingPipe, + IgxGridHierarchicalRowPinning ], exports: [ IgxGridModule, diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts index 039d54fbcc0..990b243a7d9 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts @@ -271,6 +271,7 @@ describe('IgxHierarchicalGrid Basic Navigation #hGrid', () => { })); it('should scroll top of child grid into view when pressing Ctrl + Arrow Up when cell is selected in it.', (async () => { + pending('related to the bug #7118'); hierarchicalGrid.verticalScrollContainer.scrollTo(7); fixture.detectChanges(); await wait(DEBOUNCE_TIME); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.pipes.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.pipes.ts index e498842ff6b..ac50ac977bd 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.pipes.ts @@ -77,3 +77,30 @@ export class IgxGridHierarchicalPagingPipe implements PipeTransform { return result; } } + +/** + * @hidden + */ +@Pipe({ + name: 'gridHierarchicalRowPinning', + pure: true +}) +export class IgxGridHierarchicalRowPinning implements PipeTransform { + + constructor(private gridAPI: GridBaseAPIService) { } + + public transform(collection: any[], pinnedArea: boolean, pipeTrigger: number): any[] { + const grid = this.gridAPI.grid; + + if (grid.hasPinnedRecords && pinnedArea) { + return collection.filter(rec => grid.isRecordPinned(rec)); + } + + if (grid.childLayoutKeys.length) { + return collection.map((rec) => { + return grid.isRecordPinned(rec) ? { recordRef: rec, ghostRecord: true} : rec; + }); + } + return collection.filter(rec => !grid.isRecordPinned(rec)); + } +} diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts index c243f493360..9fc4ccb7847 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts @@ -13,6 +13,7 @@ import { FilteringExpressionsTree } from '../../data-operations/filtering-expres import { FilteringLogic } from '../../data-operations/filtering-expression.interface'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; import { GridFunctions } from '../../test-utils/grid-functions.spec'; +import { HierarchicalGridFunctions } from '../../test-utils/hierarchical-grid-functions.spec'; describe('IgxHierarchicalGrid Virtualization #hGrid', () => { configureTestSuite(); @@ -386,9 +387,9 @@ describe('IgxHierarchicalGrid Virtualization Custom Scenarios #hGrid', () => { await wait(); const hierarchicalGrid = fixture.componentInstance.hgrid; - const initialBodyWidth = hierarchicalGrid.tbody.nativeElement.offsetWidth; - expect(hierarchicalGrid.verticalScrollContainer.getScroll().parentElement.hidden).toBeTruthy(); + const verticalScrollWrapper = HierarchicalGridFunctions.getVerticalScrollWrapper(fixture, hierarchicalGrid.id); + expect(verticalScrollWrapper.hidden).toBeTruthy(); // expand 1st row const row = hierarchicalGrid.dataRowList.toArray()[0]; @@ -396,13 +397,15 @@ describe('IgxHierarchicalGrid Virtualization Custom Scenarios #hGrid', () => { fixture.detectChanges(); await wait(200); - expect(hierarchicalGrid.verticalScrollContainer.getScroll().parentElement.hidden).toBeTruthy(); + expect(verticalScrollWrapper.hidden).toBeTruthy(); expect(hierarchicalGrid.tbody.nativeElement.offsetWidth).toEqual(initialBodyWidth); + const childGrid = hierarchicalGrid.hgridAPI.getChildGrids(false)[0]; childGrid.data = fixture.componentInstance.generateData(10, 0); fixture.detectChanges(); await wait(200); - expect(hierarchicalGrid.verticalScrollContainer.getScroll().parentElement.hidden).toBeFalsy(); + + expect(verticalScrollWrapper.hidden).toBeFalsy(); expect(hierarchicalGrid.tbody.nativeElement.offsetWidth).toBeLessThan(initialBodyWidth); }); }); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.html b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.html index cfdd52a3468..f7993806da2 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.html +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-row.component.html @@ -1,4 +1,4 @@ -
+
@@ -73,7 +73,7 @@ [readonly]="true" [checked]="selected" disableRipple="true" - [disabled]="deleted" + [disabled]="disabled || deleted" [disableTransitions]="grid.disableTransitions" [aria-label]="rowCheckboxAriaLabel"> 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 6c2afd9157d..54bd432717d 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 @@ -7,7 +7,9 @@ import { ViewChildren, QueryList, ViewChild, - TemplateRef + TemplateRef, + Input, + HostListener } from '@angular/core'; import { IgxHierarchicalGridComponent } from './hierarchical-grid.component'; import { IgxRowDirective } from '../row.directive'; @@ -21,6 +23,19 @@ import { IgxHierarchicalGridCellComponent } from './hierarchical-cell.component' providers: [{ provide: IgxRowDirective, useExisting: forwardRef(() => IgxHierarchicalRowComponent) }] }) export class IgxHierarchicalRowComponent extends IgxRowDirective { + + protected expanderClass = 'igx-grid__hierarchical-expander'; + + /** + * @hidden + */ + public get expanderClassResolved() { + return { + [this.expanderClass]: !this.pinned || this.disabled, + [`${this.expanderClass}--empty`]: this.pinned && !this.disabled + }; + } + @ViewChildren(forwardRef(() => IgxHierarchicalGridCellComponent), { read: IgxHierarchicalGridCellComponent }) protected _cells: QueryList; @@ -55,11 +70,18 @@ export class IgxHierarchicalRowComponent extends IgxRowDirective implements DoCheck { - private _rowData: any; + protected _rowData: any; + /** * The data passed to the row component. * @@ -58,6 +59,17 @@ export class IgxRowDirective implemen @Input() public index: number; + /** + * Sets whether this specific row has disabled functionality for editing and row selection. + * Default value is `false`. + * ```typescript + * this.grid.selectedRows[0].pinned = true; + * ``` + */ + @Input() + @HostBinding('class.igx-grid__tr--disabled') + public disabled = false; + /** * Gets whether the row is pinned. * ```typescript @@ -324,7 +336,7 @@ export class IgxRowDirective implemen */ @HostListener('click', ['$event']) public onClick(event: MouseEvent) { - if (this.grid.rowSelection === 'none' || this.deleted) { return; } + if (this.grid.rowSelection === 'none' || this.deleted || this.disabled) { return; } if (event.shiftKey && this.grid.rowSelection === 'multiple') { this.selectionService.selectMultipleRows(this.rowID, this.rowData, event); return; @@ -336,6 +348,7 @@ export class IgxRowDirective implemen * @hidden */ public onRowSelectorClick(event) { + if (this.disabled) { return; } event.stopPropagation(); if (event.shiftKey && this.grid.rowSelection === 'multiple') { this.selectionService.selectMultipleRows(this.rowID, this.rowData, event); diff --git a/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts b/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts index e9439545ffa..6f77c3e49a5 100644 --- a/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-components.spec.ts @@ -4,10 +4,12 @@ import { IgxColumnComponent } from '../grids'; import { IgxHierarchicalTransactionServiceFactory } from '../grids/hierarchical-grid/hierarchical-grid-base.directive'; import { IgxHierarchicalGridComponent } from '../grids/hierarchical-grid/hierarchical-grid.component'; import { IgxRowIslandComponent } from '../grids/hierarchical-grid/row-island.component'; +import { IPinningConfig } from '../grids/common/grid.interface'; +import { ColumnPinningPosition, RowPinningPosition } from '../grids/common/enums'; @Component({ template: ` - @@ -40,10 +42,18 @@ import { IgxRowIslandComponent } from '../grids/hierarchical-grid/row-island.com providers: [ IgxHierarchicalTransactionServiceFactory ] }) export class IgxHierarchicalGridTestBaseComponent { + + @ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true }) + public hgrid: IgxHierarchicalGridComponent; + + @ViewChild('rowIsland', { read: IgxRowIslandComponent, static: true }) + public rowIsland: IgxRowIslandComponent; + + @ViewChild('rowIsland2', { read: IgxRowIslandComponent, static: true }) + public rowIsland2: IgxRowIslandComponent; + public data; - @ViewChild('hierarchicalGrid', { read: IgxHierarchicalGridComponent, static: true }) public hgrid: IgxHierarchicalGridComponent; - @ViewChild('rowIsland', { read: IgxRowIslandComponent, static: true }) public rowIsland: IgxRowIslandComponent; - @ViewChild('rowIsland2', { read: IgxRowIslandComponent, static: true }) public rowIsland2: IgxRowIslandComponent; + public pinningConfig: IPinningConfig = { columns: ColumnPinningPosition.Start, rows: RowPinningPosition.Top }; constructor() { // 3 level hierarchy diff --git a/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-functions.spec.ts b/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-functions.spec.ts index 60cfded27b6..3cdbf3bb099 100644 --- a/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-functions.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/hierarchical-grid-functions.spec.ts @@ -4,7 +4,9 @@ import { By } from '@angular/platform-browser'; import { IgxHierarchicalRowComponent } from '../grids/hierarchical-grid/hierarchical-row.component'; import { IgxRowDirective } from '../grids/row.directive'; +const HIERARCHICAL_GRID_TAG = 'igx-hierarchical-grid'; const EXPANDER_CLASS = 'igx-grid__hierarchical-expander'; +const SCROLL_TBODY_CLASS = 'igx-grid__tbody-scrollbar'; export class HierarchicalGridFunctions { @@ -49,4 +51,15 @@ export class HierarchicalGridFunctions { public static isExpander(element: HTMLElement, modifier?: string): boolean { return element.classList.contains(`${EXPANDER_CLASS}${modifier || ''}`); } + + /** + * Gets the main wrapper element of the vertical scrollbar. + * @param fix the ComponentFixture to search + */ + public static getVerticalScrollWrapper(fix: ComponentFixture, gridID): HTMLElement { + const gridDebugEl = fix.debugElement.query(By.css(HIERARCHICAL_GRID_TAG + `[id='${gridID}'`)); + const scrollWrappers = gridDebugEl.queryAll(By.css('.' + SCROLL_TBODY_CLASS)); + // Return the last element since the scrollbar for the targeted grid is after all children that also have scrollbars + return scrollWrappers[scrollWrappers.length - 1].nativeElement; + } } diff --git a/src/app/grid-row-pinning/grid-row-pinning.sample.html b/src/app/grid-row-pinning/grid-row-pinning.sample.html index 3694eb401ed..841e3c02ef1 100644 --- a/src/app/grid-row-pinning/grid-row-pinning.sample.html +++ b/src/app/grid-row-pinning/grid-row-pinning.sample.html @@ -6,6 +6,10 @@
+
+ + Current: {{displayDensityOptions.displayDensity}} +
@@ -35,5 +39,31 @@
+
+ + + + + + + + {{cell.row.pinned ? 'lock' : 'lock_open'}} + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/src/app/grid-row-pinning/grid-row-pinning.sample.ts b/src/app/grid-row-pinning/grid-row-pinning.sample.ts index 66df6272f90..75b23e05e9a 100644 --- a/src/app/grid-row-pinning/grid-row-pinning.sample.ts +++ b/src/app/grid-row-pinning/grid-row-pinning.sample.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit, ViewChild, Inject } from '@angular/core'; import { IgxGridComponent, ColumnPinningPosition, @@ -7,7 +7,11 @@ import { IgxGridTransaction, IgxGridStateDirective, IgxExcelExporterService, - IgxExcelExporterOptions + IgxExcelExporterOptions, + DisplayDensityToken, + DisplayDensity, + IgxHierarchicalGridComponent, + IDisplayDensityOptions } from 'igniteui-angular'; import { IPinningConfig } from 'projects/igniteui-angular/src/lib/grids/common/grid.interface'; import { IgxIconService } from 'projects/igniteui-angular/src/lib/icon/icon.service'; @@ -16,10 +20,13 @@ import icons from 'projects/igniteui-angular/src/lib/grids/filtering/svgIcons'; const FILTERING_ICONS_FONT_SET = 'filtering-icons'; @Component({ - providers: [{ provide: IgxGridTransaction, useClass: IgxTransactionService }], selector: 'app-grid-row-pinning-sample', styleUrls: ['grid-row-pinning.sample.css'], - templateUrl: 'grid-row-pinning.sample.html' + templateUrl: 'grid-row-pinning.sample.html', + providers: [ + { provide: IgxGridTransaction, useClass: IgxTransactionService }, + { provide: DisplayDensityToken, useValue: { displayDensity: DisplayDensity.comfortable} } + ], }) export class GridRowPinningSampleComponent implements OnInit { @@ -41,9 +48,12 @@ export class GridRowPinningSampleComponent implements OnInit { @ViewChild('grid1', { static: true }) grid1: IgxGridComponent; + @ViewChild('hGrid', { static: true }) + hGrid: IgxHierarchicalGridComponent; + @ViewChild(IgxGridStateDirective, { static: true }) public state: IgxGridStateDirective; - constructor(private excelExportService: IgxExcelExporterService, private iconService: IgxIconService) { + constructor(@Inject(DisplayDensityToken) public displayDensityOptions: IDisplayDensityOptions, private iconService: IgxIconService, private excelExportService: IgxExcelExporterService) { } onRowChange() { @@ -63,7 +73,9 @@ export class GridRowPinningSampleComponent implements OnInit { } data: any[]; + hierarchicalData: any[]; columns: any[]; + hColumns: any[]; ngOnInit(): void { this.columns = [ @@ -79,6 +91,18 @@ export class GridRowPinningSampleComponent implements OnInit { { field: 'Fax', width: '200px' } ]; + this.hColumns = [ + { field: 'ID', width: '200px' }, + { field: 'ChildLevels', width: '200px' }, + { field: 'ProductName', width: '200px' }, + { field: 'Col1', width: '200px' }, + { field: 'Col2', width: '200px' }, + { field: 'Col3', width: '200px' }, + { field: 'childData', width: '200px' }, + { field: 'childData2', width: '200px' }, + { field: 'hasChild', width: '200px' } + ] + this.data = [ // tslint:disable:max-line-length { 'ID': 'ALFKI', 'CompanyName': 'Alfreds Futterkiste', 'ContactName': 'Maria Anders', 'ContactTitle': 'Sales Representative', 'Address': 'Obere Str. 57', 'City': 'Berlin', 'Region': null, 'PostalCode': '12209', 'Country': 'Germany', 'Phone': '030-0074321', 'Fax': '030-0076545' }, @@ -109,6 +133,8 @@ export class GridRowPinningSampleComponent implements OnInit { { 'ID': 'FRANR', 'CompanyName': 'France restauration', 'ContactName': 'Carine Schmitt', 'ContactTitle': 'Marketing Manager', 'Address': '54, rue Royale', 'City': 'Nantes', 'Region': null, 'PostalCode': '44000', 'Country': 'France', 'Phone': '40.32.21.21', 'Fax': '40.32.21.20' }, { 'ID': 'FRANS', 'CompanyName': 'Franchi S.p.A.', 'ContactName': 'Paolo Accorti', 'ContactTitle': 'Sales Representative', 'Address': 'Via Monte Bianco 34', 'City': 'Torino', 'Region': null, 'PostalCode': '10100', 'Country': 'Italy', 'Phone': '011-4988260', 'Fax': '011-4988261' } ]; + this.hierarchicalData = this.generateDataUneven(100, 3); + this // tslint:enable:max-line-length } @@ -137,6 +163,40 @@ export class GridRowPinningSampleComponent implements OnInit { } } + clickUnpin() { + this.grid1.unpinRow('aaaa'); + } + + generateDataUneven(count: number, level: number, parendID: string = null) { + const prods = []; + const currLevel = level; + let children; + for (let i = 0; i < count; i++) { + const rowID = parendID ? parendID + i : i.toString(); + if (level > 0) { + // Have child grids for row with even id less rows by not multiplying by 2 + children = this.generateDataUneven(((i % 2) + 1) * Math.round(count / 3), currLevel - 1, rowID); + } + prods.push({ + ID: rowID, + ChildLevels: currLevel, + ProductName: 'Product: A' + i, + Col1: i, + Col2: i, + Col3: i, + childData: children, + childData2: children, + hasChild: true + }); + } + return prods; + } + + public isPinned(cell) { + console.log(cell); + return true; + } + public exportButtonHandler() { this.excelExportService.export(this.grid1, new IgxExcelExporterOptions("ExportFileFromGrid")); } @@ -150,4 +210,12 @@ export class GridRowPinningSampleComponent implements OnInit { const state = window.localStorage.getItem("grid1-state"); this.state.setState(state); } + + toggleDensity() { + switch (this.displayDensityOptions.displayDensity ) { + case DisplayDensity.comfortable: this.displayDensityOptions.displayDensity = DisplayDensity.compact; break; + case DisplayDensity.compact: this.displayDensityOptions.displayDensity = DisplayDensity.cosy; break; + case DisplayDensity.cosy: this.displayDensityOptions.displayDensity = DisplayDensity.comfortable; break; + } + } }