diff --git a/CHANGELOG.md b/CHANGELOG.md index b34431f83c1..6c0327677a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,26 @@ All notable changes for each version of this project will be documented in this ```ts this.carousel.select(2, Direction.NEXT); ``` +- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid` + - Added ability to pin individual columns to a specific side (start or end of the grid), so that you can now have pinning from both sides. This can be done either declaratively by setting the `pinningPosition` property on the column: + + ```html + + + ``` + + ```ts + public pinningPosition = ColumnPinningPosition.End; + ``` + + Or with the API, via optional parameter: + + ```ts + grid.pinColumn('Col1', 0, ColumnPinningPosition.End); + grid.pinColumn('Col2', 0, ColumnPinningPosition.Start); + ``` + + If property `pinningPosition` is not set on a column, the column will default to the position specified on the grid's `pinning` options for `columns`. ### General - `IgxDropDown` now exposes a `role` input property, allowing users to customize the role attribute based on the use case. The default is `listbox`. diff --git a/projects/igniteui-angular/src/lib/grids/columns/column-layout.component.ts b/projects/igniteui-angular/src/lib/grids/columns/column-layout.component.ts index 1e303325cb2..c3641bfe13f 100644 --- a/projects/igniteui-angular/src/lib/grids/columns/column-layout.component.ts +++ b/projects/igniteui-angular/src/lib/grids/columns/column-layout.component.ts @@ -82,15 +82,10 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements } const unpinnedColumns = this.grid.unpinnedColumns.filter(c => c.columnLayout && !c.hidden); - const pinnedColumns = this.grid.pinnedColumns.filter(c => c.columnLayout && !c.hidden); - let vIndex = -1; - - if (!this.pinned) { - const indexInCollection = unpinnedColumns.indexOf(this); - vIndex = indexInCollection === -1 ? -1 : pinnedColumns.length + indexInCollection; - } else { - vIndex = pinnedColumns.indexOf(this); - } + const pinnedStart = this.grid.pinnedStartColumns.filter(c => c.columnLayout && !c.hidden); + const pinnedEndColumns = this.grid.pinnedEndColumns.filter(c => c.columnLayout && !c.hidden); + const ordered = pinnedStart.concat(unpinnedColumns).concat(pinnedEndColumns); + let vIndex = ordered.indexOf(this); this._vIndex = vIndex; return vIndex; } @@ -158,7 +153,7 @@ export class IgxColumnLayoutComponent extends IgxColumnGroupComponent implements public override populateVisibleIndexes() { this.childrenVisibleIndexes = []; const columns = this.grid?.pinnedColumns && this.grid?.unpinnedColumns - ? this.grid.pinnedColumns.concat(this.grid.unpinnedColumns) + ? this.grid.pinnedStartColumns.concat(this.grid.unpinnedColumns).concat(this.grid.pinnedEndColumns) : []; const orderedCols = columns .filter(x => !x.columnGroup && !x.hidden) diff --git a/projects/igniteui-angular/src/lib/grids/columns/column.component.ts b/projects/igniteui-angular/src/lib/grids/columns/column.component.ts index 641c2fb5a0c..5dc8013634e 100644 --- a/projects/igniteui-angular/src/lib/grids/columns/column.component.ts +++ b/projects/igniteui-angular/src/lib/grids/columns/column.component.ts @@ -56,7 +56,7 @@ import { IColumnVisibilityChangingEventArgs, IPinColumnCancellableEventArgs, IPi import { isConstructor, PlatformUtil } from '../../core/utils'; import { IgxGridCell } from '../grid-public-cell'; import { NG_VALIDATORS, Validator } from '@angular/forms'; -import { Size } from '../common/enums'; +import { ColumnPinningPosition, Size } from '../common/enums'; import { ExpressionsTreeUtil } from '../../data-operations/expressions-tree-util'; const DEFAULT_DATE_FORMAT = 'mediumDate'; @@ -1039,6 +1039,28 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy return (this.grid as any)._columns.indexOf(this); } + /** + * Gets the pinning position of the column. + * ```typescript + * let pinningPosition = this.column.pinningPosition; + */ + @WatchColumnChanges() + @Input() + public get pinningPosition(): ColumnPinningPosition { + const userSet = this._pinningPosition !== null && this._pinningPosition !== undefined; + return userSet ? this._pinningPosition : this.grid.pinning.columns; + } + + /** + * Sets the pinning position of the column. + *```html + * + * ``` + */ + public set pinningPosition(value: ColumnPinningPosition) { + this._pinningPosition = value; + } + /** * Gets whether the column is `pinned`. * ```typescript @@ -1485,7 +1507,8 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy return this._vIndex; } const unpinnedColumns = this.grid.unpinnedColumns.filter(c => !c.columnGroup); - const pinnedColumns = this.grid.pinnedColumns.filter(c => !c.columnGroup); + const pinnedStartColumns = this.grid.pinnedStartColumns.filter(c => !c.columnGroup); + const pinnedEndColumns = this.grid.pinnedEndColumns.filter(c => !c.columnGroup); let col = this; let vIndex = -1; @@ -1500,15 +1523,13 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy if (!this.pinned) { const indexInCollection = unpinnedColumns.indexOf(col); vIndex = indexInCollection === -1 ? - -1 : - (this.grid.isPinningToStart ? - pinnedColumns.length + indexInCollection : - indexInCollection); + -1 : pinnedStartColumns.length + indexInCollection; } else { - const indexInCollection = pinnedColumns.indexOf(col); - vIndex = this.grid.isPinningToStart ? + const indexInCollection = this.pinningPosition === ColumnPinningPosition.Start ? + pinnedStartColumns.indexOf(col) : pinnedEndColumns.indexOf(col); + vIndex = this.pinningPosition === ColumnPinningPosition.Start ? indexInCollection : - unpinnedColumns.length + indexInCollection; + pinnedStartColumns.length + unpinnedColumns.length + indexInCollection; } this._vIndex = vIndex; return vIndex; @@ -1586,20 +1607,20 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy /** @hidden @internal **/ public get isLastPinned(): boolean { - return this.grid.isPinningToStart && - this.grid.pinnedColumns[this.grid.pinnedColumns.length - 1] === this; + return this.pinningPosition === ColumnPinningPosition.Start && + this.grid.pinnedStartColumns[this.grid.pinnedStartColumns.length - 1] === this; } /** @hidden @internal **/ public get isFirstPinned(): boolean { - const pinnedCols = this.grid.pinnedColumns.filter(x => !x.columnGroup); - return !this.grid.isPinningToStart && pinnedCols[0] === this; + const pinnedCols = this.grid.pinnedEndColumns.filter(x => !x.columnGroup); + return this.pinningPosition === ColumnPinningPosition.End && pinnedCols[0] === this; } /** @hidden @internal **/ public get rightPinnedOffset(): string { - return this.pinned && !this.grid.isPinningToStart ? - - this.grid.pinnedWidth - this.grid.headerFeaturesWidth + 'px' : + return this.pinned && this.pinningPosition === ColumnPinningPosition.End ? + - this.grid.pinnedEndWidth - this.grid.pinnedStartWidth + 'px' : null; } @@ -1792,6 +1813,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy protected _applySelectableClass = false; protected _vIndex = NaN; + protected _pinningPosition = null; /** * @hidden */ @@ -2185,20 +2207,19 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy } /** - * Pins the column at the provided index in the pinned area. + * Pins the column in the specified position at the provided index in that pinned area. * Defaults to index `0` if not provided, or to the initial index in the pinned area. * Returns `true` if the column is successfully pinned. Returns `false` if the column cannot be pinned. * Column cannot be pinned if: * - Is already pinned * - index argument is out of range - * - The pinned area exceeds 80% of the grid width * ```typescript * let success = this.column.pin(); * ``` * * @memberof IgxColumnComponent */ - public pin(index?: number): boolean { + public pin(index?: number, pinningPosition?: ColumnPinningPosition): boolean { // TODO: Probably should the return type of the old functions // should be moved as a event parameter. const grid = (this.grid as any); @@ -2207,11 +2228,15 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy } if (this.parent && !this.parent.pinned) { - return this.topLevelParent.pin(index); - } - - const hasIndex = index !== undefined; - if (hasIndex && (index < 0 || index > grid.pinnedColumns.length)) { + return this.topLevelParent.pin(index, pinningPosition); + } + const targetPinPosition = pinningPosition !== null && pinningPosition !== undefined ? pinningPosition : this.pinningPosition; + const pinningVisibleCollection = targetPinPosition === ColumnPinningPosition.Start ? + grid.pinnedStartColumns : grid.pinnedEndColumns; + const pinningCollection = targetPinPosition === ColumnPinningPosition.Start ? + grid._pinnedStartColumns : grid._pinnedEndColumns; + const hasIndex = index !== undefined && index !== null; + if (hasIndex && (index < 0 || index > pinningVisibleCollection.length)) { return false; } @@ -2219,7 +2244,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy return false; } - const rootPinnedCols = grid._pinnedColumns.filter((c) => c.level === 0); + const rootPinnedCols = pinningCollection.filter((c) => c.level === 0); index = hasIndex ? index : rootPinnedCols.length; const args: IPinColumnCancellableEventArgs = { column: this, insertAtIndex: index, isPinned: false, cancel: false }; this.grid.columnPin.emit(args); @@ -2231,14 +2256,20 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy this.grid.crudService.endEdit(false); this._pinned = true; + if (pinningPosition !== null && pinningPosition !== undefined) { + // if user has set some position in the params, overwrite the column's position. + this._pinningPosition = pinningPosition; + } + this.pinnedChange.emit(this._pinned); // it is possible that index is the last position, so will need to find target column by [index-1] - const targetColumn = args.insertAtIndex === grid._pinnedColumns.length ? - grid._pinnedColumns[args.insertAtIndex - 1] : grid._pinnedColumns[args.insertAtIndex]; + const targetColumn = args.insertAtIndex === pinningCollection.length ? + pinningCollection[args.insertAtIndex - 1] : pinningCollection[args.insertAtIndex]; - if (grid._pinnedColumns.indexOf(this) === -1) { + if (pinningCollection.indexOf(this) === -1) { if (!grid.hasColumnGroups) { - grid._pinnedColumns.splice(args.insertAtIndex, 0, this); + pinningCollection.splice(args.insertAtIndex, 0, this); + grid._pinnedColumns = grid._pinnedStartColumns.concat(grid._pinnedEndColumns); } else { // insert based only on root collection if (this.level === 0) { @@ -2252,6 +2283,11 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy allPinned = allPinned.concat(group.allChildren); }); grid._pinnedColumns = allPinned; + if (this.pinningPosition === ColumnPinningPosition.Start) { + grid._pinnedStartColumns = allPinned; + } else { + grid._pinnedEndColumns = allPinned; + } } if (grid._unpinnedColumns.indexOf(this) !== -1) { @@ -2261,12 +2297,12 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy } if (hasIndex) { - index === grid._pinnedColumns.length - 1 ? + index === pinningCollection.length - 1 ? grid._moveColumns(this, targetColumn, DropPosition.AfterDropTarget) : grid._moveColumns(this, targetColumn, DropPosition.BeforeDropTarget); } if (this.columnGroup) { - this.allChildren.forEach(child => child.pin()); + this.allChildren.forEach(child => child.pin(null, targetPinPosition)); grid.reinitPinStates(); } @@ -2302,7 +2338,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy if (this.parent && this.parent.pinned) { return this.topLevelParent.unpin(index); } - const hasIndex = index !== undefined; + const hasIndex = index !== undefined && index !== null; if (hasIndex && (index < 0 || index > grid._unpinnedColumns.length)) { return false; } @@ -2337,6 +2373,12 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy if (grid._pinnedColumns.indexOf(this) !== -1) { grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1); } + if (this.pinningPosition === ColumnPinningPosition.Start && grid._pinnedStartColumns.indexOf(this) !== -1) { + grid._pinnedStartColumns.splice(grid._pinnedStartColumns.indexOf(this), 1); + } + if (this.pinningPosition === ColumnPinningPosition.End && grid._pinnedEndColumns.indexOf(this) !== -1) { + grid._pinnedEndColumns.splice(grid._pinnedEndColumns.indexOf(this), 1); + } } if (hasIndex) { 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 3c8d8aa4f38..d70719b7844 100644 --- a/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts +++ b/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts @@ -520,7 +520,7 @@ export interface ColumnType extends FieldType { toggleVisibility(value?: boolean): void; populateVisibleIndexes?(): void; /** Pins the column at the specified index (if not already pinned). */ - pin(index?: number): boolean; + pin(index?: number, pinningPosition?: ColumnPinningPosition): boolean; /** Unpins the column at the specified index (if not already unpinned). */ unpin(index?: number): boolean; } @@ -776,13 +776,13 @@ export interface GridType extends IGridDataBindable { isRowSelectable: boolean; /** Indicates whether the selectors of the rows are visible */ showRowSelectors: boolean; - /** Indicates whether the grid's element is pinned to the start of the grid */ - isPinningToStart: boolean; /** Indicates if the column of the grid is in drag mode */ columnInDrag: any; /** @hidden @internal */ - /** The width of pinned element */ - pinnedWidth: number; + /** The width of pinned element for pinning at start. */ + pinnedStartWidth: number; + /** The width of pinned element for pinning at end. */ + pinnedEndWidth: number; /** @hidden @internal */ /** The width of unpinned element */ unpinnedWidth: number; @@ -917,6 +917,10 @@ export interface GridType extends IGridDataBindable { unpinnedColumns: ColumnType[]; /** An array of columns, but it counts only the ones that are pinned */ pinnedColumns: ColumnType[]; + /** An array of columns, but it counts only the ones that are pinned to the start. */ + pinnedStartColumns: ColumnType[]; + /** An array of columns, but it counts only the ones that are pinned to the end. */ + pinnedEndColumns: ColumnType[]; /** represents an array of the headers of the columns */ /** @hidden @internal */ headerCellList: any[]; diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-moving.component.ts b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-moving.component.ts index 80aa1564310..3604c63b44e 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-moving.component.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-moving.component.ts @@ -4,6 +4,7 @@ import { BaseFilteringComponent } from './base-filtering.component'; import { IgxIconComponent } from '../../../icon/icon.component'; import { IgxButtonDirective } from '../../../directives/button/button.directive'; import { IgxButtonGroupComponent } from '../../../buttonGroup/buttonGroup.component'; +import { ColumnPinningPosition } from '../../common/enums'; /** * A component used for presenting Excel style column moving UI. @@ -49,25 +50,26 @@ export class IgxExcelStyleMovingComponent { public onMoveButtonClicked(moveDirection) { let targetColumn; if (this.esf.column.pinned) { - if (this.esf.column.isLastPinned && moveDirection === 1 && this.esf.grid.isPinningToStart) { + if (this.esf.column.isLastPinned && moveDirection === 1 && this.esf.column.pinningPosition === ColumnPinningPosition.Start) { targetColumn = this.esf.grid.unpinnedColumns[0]; moveDirection = 0; - } else if (this.esf.column.isFirstPinned && moveDirection === 0 && !this.esf.grid.isPinningToStart) { + } else if (this.esf.column.isFirstPinned && moveDirection === 0 && this.esf.column.pinningPosition === ColumnPinningPosition.End) { targetColumn = this.esf.grid.unpinnedColumns[this.esf.grid.unpinnedColumns.length - 1]; moveDirection = 1; } else { targetColumn = this.findColumn(moveDirection, this.esf.grid.pinnedColumns); } - } else if (this.esf.grid.unpinnedColumns.indexOf(this.esf.column) === 0 && moveDirection === 0 && - this.esf.grid.isPinningToStart) { - targetColumn = this.esf.grid.pinnedColumns[this.esf.grid.pinnedColumns.length - 1]; + } else if (this.esf.grid.unpinnedColumns.indexOf(this.esf.column) === 0 && moveDirection === 0) { + // moving first unpinned, left (into pin start area) + targetColumn = this.esf.grid.pinnedStartColumns[this.esf.grid.pinnedStartColumns.length - 1]; if (targetColumn.parent) { targetColumn = targetColumn.topLevelParent; } moveDirection = 1; } else if (this.esf.grid.unpinnedColumns.indexOf(this.esf.column) === this.esf.grid.unpinnedColumns.length - 1 && - moveDirection === 1 && !this.esf.grid.isPinningToStart) { - targetColumn = this.esf.grid.pinnedColumns[0]; + moveDirection === 1) { + // moving last unpinned, right (into pin end area) + targetColumn = this.esf.grid.pinnedEndColumns[0]; moveDirection = 0; } else { targetColumn = this.findColumn(moveDirection, this.esf.grid.unpinnedColumns); 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 c18341a7159..e4a919df1cb 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.directive.ts @@ -2645,14 +2645,6 @@ export abstract class IgxGridBaseDirective implements GridType, this._headSelectorTemplate = template; } - /** - * @hidden - * @internal - */ - public get isPinningToStart() { - return this.pinning.columns !== ColumnPinningPosition.End; - } - /** * @hidden * @internal @@ -3124,6 +3116,17 @@ export abstract class IgxGridBaseDirective implements GridType, * @hidden */ protected _pinnedColumns: IgxColumnComponent[] = []; + + /** + * @hidden + */ + protected _pinnedStartColumns: IgxColumnComponent[] = []; + + /** + * @hidden + */ + protected _pinnedEndColumns: IgxColumnComponent[] = []; + /** * @hidden */ @@ -3262,7 +3265,8 @@ export abstract class IgxGridBaseDirective implements GridType, private _totalWidth = NaN; private _pinnedVisible = []; private _unpinnedVisible = []; - private _pinnedWidth = NaN; + private _pinnedStartWidth = NaN; + private _pinnedEndWidth = NaN; private _unpinnedWidth = NaN; private _visibleColumns = []; private _columnGroups = false; @@ -3910,7 +3914,8 @@ export abstract class IgxGridBaseDirective implements GridType, */ public resetCachedWidths() { this._unpinnedWidth = NaN; - this._pinnedWidth = NaN; + this._pinnedStartWidth = NaN; + this._pinnedEndWidth = NaN; this._totalWidth = NaN; } @@ -4419,12 +4424,21 @@ export abstract class IgxGridBaseDirective implements GridType, } /** @hidden @internal */ - public get pinnedWidth() { - if (!isNaN(this._pinnedWidth)) { - return this._pinnedWidth; + public get pinnedStartWidth() { + if (!isNaN(this._pinnedStartWidth)) { + return this._pinnedStartWidth; + } + this._pinnedStartWidth = this.getPinnedStartWidth(); + return this._pinnedStartWidth; + } + + /** @hidden @internal */ + public get pinnedEndWidth() { + if (!isNaN(this._pinnedEndWidth)) { + return this._pinnedEndWidth; } - this._pinnedWidth = this.getPinnedWidth(); - return this._pinnedWidth; + this._pinnedEndWidth = this.getPinnedEndWidth(); + return this._pinnedEndWidth; } /** @hidden @internal */ @@ -4515,6 +4529,30 @@ export abstract class IgxGridBaseDirective implements GridType, return this._pinnedVisible; } + /** + * Gets an array of the pinned to the left `IgxColumnComponent`s. + * + * @example + * ```typescript + * const pinnedColumns = this.grid.pinnedStartColumns. + * ``` + */ + public get pinnedStartColumns(): IgxColumnComponent[] { + return this._pinnedStartColumns.filter(col => !col.hidden); + } + + /** + * Gets an array of the pinned to the right `IgxColumnComponent`s. + * + * @example + * ```typescript + * const pinnedColumns = this.grid.pinnedEndColumns. + * ``` + */ + public get pinnedEndColumns(): IgxColumnComponent[] { + return this._pinnedEndColumns.filter(col => !col.hidden); + } + /* csSuppress */ /** * Gets an array of the pinned `IgxRowComponent`s. @@ -4730,9 +4768,9 @@ export abstract class IgxGridBaseDirective implements GridType, // pinning and unpinning will work correctly even without passing index // but is easier to calclulate the index here, and later use it in the pinning event args if (target.pinned && !column.pinned) { - const pinnedIndex = this._pinnedColumns.indexOf(target); + const pinnedIndex = target.pinningPosition === ColumnPinningPosition.Start ? this.pinnedStartColumns.indexOf(target) : this.pinnedEndColumns.indexOf(target); const index = pos === DropPosition.AfterDropTarget ? pinnedIndex + 1 : pinnedIndex; - column.pin(index); + column.pin(index, target.pinningPosition); } if (!target.pinned && column.pinned) { @@ -4741,6 +4779,11 @@ export abstract class IgxGridBaseDirective implements GridType, column.unpin(index); } + // both are pinned but are in different sides + if (target.pinned && column.pinned && target.pinningPosition !== column.pinningPosition) { + column.pinningPosition = target.pinningPosition; + } + // if (target.pinned && column.pinned && !columnPinStateChanged) { // this._reorderColumns(column, target, pos, this._pinnedColumns); // } @@ -5138,10 +5181,11 @@ export abstract class IgxGridBaseDirective implements GridType, * ``` * @param columnName * @param index + * @param pinningPosition */ - public pinColumn(columnName: string | IgxColumnComponent, index?: number): boolean { + public pinColumn(columnName: string | IgxColumnComponent, index?: number, pinningPosition?: ColumnPinningPosition): boolean { const col = columnName instanceof IgxColumnComponent ? columnName : this.getColumnByName(columnName); - return col.pin(index); + return col.pin(index, pinningPosition); } /** @@ -5552,7 +5596,7 @@ export abstract class IgxGridBaseDirective implements GridType, } /** - * Gets calculated width of the pinned area. + * Gets calculated width of the pinned areas. * * @example * ```typescript @@ -5560,17 +5604,58 @@ export abstract class IgxGridBaseDirective implements GridType, * ``` * @param takeHidden If we should take into account the hidden columns in the pinned area. */ - public getPinnedWidth(takeHidden = false) { - const fc = takeHidden ? this._pinnedColumns : this.pinnedColumns; + public getPinnedStartWidth(takeHidden = false) { + const fc = takeHidden ? this._pinnedStartColumns : this.pinnedStartColumns; let sum = 0; for (const col of fc) { if (col.level === 0) { sum += parseFloat(col.calcWidth); } } - if (this.isPinningToStart) { - sum += this.featureColumnsWidth(); + // includes features at start + sum += this.featureColumnsWidth(); + + return sum; + } + + /** + * Gets calculated width of the pinned areas. + * + * @example + * ```typescript + * const pinnedWidth = this.grid.getPinnedWidth(); + * ``` + * @param takeHidden If we should take into account the hidden columns in the pinned area. + */ + public getPinnedEndWidth(takeHidden = false) { + const fc = takeHidden ? this._pinnedEndColumns : this.pinnedEndColumns; + let sum = 0; + for (const col of fc) { + if (col.level === 0) { + sum += parseFloat(col.calcWidth); + } } + return sum; + } + + /** + * Gets calculated width of the pinned left area. + * + * @example + * ```typescript + * const pinnedWidth = this.grid.getPinnedWidth(); + * ``` + * @param takeHidden If we should take into account the hidden columns in the pinned area. + */ + public getPinnedLeftWidth(takeHidden = false) { + const fc = takeHidden ? this._pinnedStartColumns : this.pinnedStartColumns; + let sum = 0; + for (const col of fc) { + if (col.level === 0) { + sum += parseFloat(col.calcWidth); + } + } + sum += this.featureColumnsWidth(); return sum; } @@ -6678,7 +6763,7 @@ export abstract class IgxGridBaseDirective implements GridType, * @hidden */ protected _moveColumns(from: IgxColumnComponent, to: IgxColumnComponent, pos: DropPosition) { - const orderedList = this._pinnedColumns.concat(this._unpinnedColumns); + const orderedList = this._pinnedStartColumns.concat(this._unpinnedColumns).concat(this._pinnedEndColumns); const list = orderedList; this._reorderColumns(from, to, pos, list); const newList = this._resetColumnList(list); @@ -6694,6 +6779,8 @@ export abstract class IgxGridBaseDirective implements GridType, // update internal collections to retain order. this._pinnedColumns = newColumns .filter((c) => c.pinned); + this._pinnedStartColumns = newColumns.filter((c) => c.pinned && c.pinningPosition === ColumnPinningPosition.Start); + this._pinnedEndColumns = newColumns.filter((c) => c.pinned && c.pinningPosition === ColumnPinningPosition.End); this._unpinnedColumns = newColumns.filter((c) => !c.pinned); this._columns = newColumns; if (this._columns && this._columns.length && this._filteringExpressionsTree) { @@ -6847,6 +6934,11 @@ export abstract class IgxGridBaseDirective implements GridType, added = true; if (record.item.pinned) { this._pinnedColumns.push(record.item); + if (record.item.pinningPosition === ColumnPinningPosition.Start) { + this._pinnedStartColumns.push(record.item); + } else { + this._pinnedEndColumns.push(record.item); + } pinning = true; } else { this._unpinnedColumns.push(record.item); @@ -7129,11 +7221,8 @@ export abstract class IgxGridBaseDirective implements GridType, if (this.hasVerticalScroll() && !this.isPercentWidth) { width -= this.scrollSize; } - if (!this.isPinningToStart) { - width -= this.featureColumnsWidth(); - } - return width - this.getPinnedWidth(takeHidden); + return width - (this.getPinnedStartWidth(takeHidden) + this.getPinnedEndWidth(takeHidden)); } /** @@ -7261,6 +7350,10 @@ export abstract class IgxGridBaseDirective implements GridType, protected reinitPinStates() { this._pinnedColumns = this._columns .filter((c) => c.pinned).sort((a, b) => this._pinnedColumns.indexOf(a) - this._pinnedColumns.indexOf(b)); + this._pinnedStartColumns = this._columns.filter((c) => c.pinned && c.pinningPosition === ColumnPinningPosition.Start) + .sort((a, b) => this._pinnedStartColumns.indexOf(a) - this._pinnedStartColumns.indexOf(b)); + this._pinnedEndColumns = this._columns.filter((c) => c.pinned && c.pinningPosition === ColumnPinningPosition.End) + .sort((a, b) => this._pinnedEndColumns.indexOf(a) - this._pinnedEndColumns.indexOf(b)); this._unpinnedColumns = this.hasColumnGroups ? this._columns.filter((c) => !c.pinned) : this._columns.filter((c) => !c.pinned) .sort((a, b) => this._unpinnedColumns.indexOf(a) - this._unpinnedColumns.indexOf(b)); @@ -7528,9 +7621,9 @@ export abstract class IgxGridBaseDirective implements GridType, let columnIndex = typeof column === 'number' ? column : this.getColumnByName(column).visibleIndex; const scrollRow = this.rowList.find(r => !!r.virtDirRow); const virtDir = scrollRow ? scrollRow.virtDirRow : null; - if (this.isPinningToStart && this.pinnedColumns.length) { - if (columnIndex >= this.pinnedColumns.length) { - columnIndex -= this.pinnedColumns.length; + if (this.pinnedStartColumns.length) { + if (columnIndex >= this.pinnedStartColumns.length) { + columnIndex -= this.pinnedStartColumns.length; this.scrollDirective(virtDir, columnIndex); } } else { @@ -7972,6 +8065,8 @@ export abstract class IgxGridBaseDirective implements GridType, } // Assign the applicable collections. this._pinnedColumns = pinnedColumns; + this._pinnedStartColumns = pinnedColumns.filter((c) => c.pinned && c.pinningPosition === ColumnPinningPosition.Start); + this._pinnedEndColumns = pinnedColumns.filter((c) => c.pinned && c.pinningPosition === ColumnPinningPosition.End); this._unpinnedColumns = unpinnedColumns; } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-mrl-keyboard-nav.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-mrl-keyboard-nav.spec.ts index dcffd2d8e89..a4b64813680 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-mrl-keyboard-nav.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-mrl-keyboard-nav.spec.ts @@ -2191,7 +2191,7 @@ describe('IgxGrid Multi Row Layout - Keyboard navigation #grid', () => { const firstUnpinnedCell = grid.gridAPI.get_cell_by_index(0, 'ContactName'); expect(firstUnpinnedCell.active).toBe(true); const diff = firstUnpinnedCell.nativeElement.getBoundingClientRect().left - - grid.pinnedWidth - grid.tbody.nativeElement.getBoundingClientRect().left; + grid.pinnedStartWidth - grid.tbody.nativeElement.getBoundingClientRect().left; expect(diff).toBe(0); // TODO: Rest of the test needs to be finished 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 7289bc16f29..f0eecaecd20 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 @@ -25,24 +25,24 @@ @if (!grid.hasColumnLayouts) { - @if (pinnedColumns.length > 0 && grid.isPinningToStart) { - @for (col of pinnedColumns | igxNotGrouped; track trackPinnedColumn(col)) { + @if (pinnedStartColumns.length > 0) { + @for (col of pinnedStartColumns | igxNotGrouped; track trackPinnedColumn(col)) { } } - @if (pinnedColumns.length > 0 && !grid.isPinningToStart) { - @for (col of pinnedColumns | igxNotGrouped; track trackPinnedColumn(col)) { + @if (pinnedEndColumns.length > 0) { + @for (col of pinnedEndColumns | igxNotGrouped; track trackPinnedColumn(col)) { } } } @if (grid.hasColumnLayouts) { - @if (pinnedColumns.length > 0 && grid.isPinningToStart) { - + @if (pinnedStartColumns.length > 0) { + }
+ @if (pinnedEndColumns.length > 0) { + } } @@ -65,7 +65,7 @@
0) { + class="igx-grid__scroll-on-drag-pinned" [style.left.px]="pinnedStartWidth"> } @@ -180,12 +181,12 @@
-
+
-
+
- - @for (col of pinnedColumns | igxNotGrouped; track trackPinnedColumn(col)) { + + @for (col of columns | igxNotGrouped; track trackPinnedColumn(col)) { 0) { + class="igx-grid__scroll-on-drag-pinned" [style.left.px]="pinnedStartWidth"> } -
+
-
+
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 5fc9e317b65..57890443e81 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 @@ -870,8 +870,8 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni /** * @hidden @internal */ - public override get pinnedWidth() { - return super.pinnedWidth; + public override get pinnedStartWidth() { + return super.pinnedStartWidth; } /** @@ -1311,8 +1311,13 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni } /** @hidden @internal */ - public get pivotPinnedWidth() { - return !this._init ? (this.isPinningToStart ? this.pinnedWidth : this.headerFeaturesWidth) : 0; + public get pivotPinnedStartWidth() { + return !this._init ? this.pinnedStartWidth : 0; + } + + /** @hidden @internal */ + public get pivotPinnedEndWidth() { + return !this._init ? this.pinnedEndWidth : 0; } /** @hidden @internal */ @@ -1594,8 +1599,8 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni /** * @hidden @internal */ - public override getPinnedWidth(takeHidden = false) { - return super.getPinnedWidth(takeHidden); + public override getPinnedStartWidth(takeHidden = false) { + return super.getPinnedStartWidth(takeHidden); } /** diff --git a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.html b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.html index 6585cf8c3e5..5d507b28fba 100644 --- a/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.html +++ b/projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-header-row.component.html @@ -267,8 +267,8 @@ } - @if (pinnedColumnCollection.length && grid.isPinningToStart) { - @for (column of pinnedColumnCollection | igxTopLevel; track column) { + @if (pinnedStartColumnCollection.length) { + @for (column of pinnedStartColumnCollection | igxTopLevel; track column) { - @if (pinnedColumnCollection.length && !grid.isPinningToStart) { - @for (column of pinnedColumnCollection | igxTopLevel; track column) { + @if (pinnedEndColumnCollection.length) { + @for (column of pinnedEndColumnCollection | igxTopLevel; track column) {
} - @if (pinnedColumns.length > 0 && grid.isPinningToStart) { - + @if (pinnedStartColumns.length > 0) { + } - @if (pinnedColumns.length > 0 && !grid.isPinningToStart) { - + @if (pinnedEndColumns.length > 0) { + } } - - @for (col of pinnedColumns | igxNotGrouped; track trackPinnedColumn(col)) { + + @for (col of columns | igxNotGrouped; track trackPinnedColumn(col)) { } - @if (pinnedColumns.length > 0 && grid.isPinningToStart) { - + @if (pinnedStartColumns.length > 0) { + } @@ -84,8 +84,8 @@ - @if (pinnedColumns.length > 0 && !grid.isPinningToStart) { - + @if (pinnedEndColumns.length > 0) { + } @@ -104,8 +104,8 @@ - - @for (col of pinnedColumns | igxNotGrouped; track trackPinnedColumn(col)) { + + @for (col of columns | igxNotGrouped; track trackPinnedColumn(col)) { 0) { + class="igx-grid__scroll-on-drag-pinned" [style.left.px]="pinnedStartWidth"> } @if (data @@ -139,12 +140,12 @@
-
+
-
+
+ primaryKey="PostalCode" [width]="'100%'" [height]="'500px'" [moving]="true"> @@ -13,17 +13,17 @@ - + - + - + diff --git a/src/app/grid-multi-row-layout/grid-mrl.sample.ts b/src/app/grid-multi-row-layout/grid-mrl.sample.ts index cffe9e55dd2..1f3821ace4c 100644 --- a/src/app/grid-multi-row-layout/grid-mrl.sample.ts +++ b/src/app/grid-multi-row-layout/grid-mrl.sample.ts @@ -1,5 +1,5 @@ import { Component, HostBinding, ViewChild } from '@angular/core'; -import { GridSelectionMode, IgxActionStripComponent, IgxButtonDirective, IgxButtonGroupComponent, IgxColumnComponent, IgxColumnLayoutComponent, IgxGridComponent, IgxGridEditingActionsComponent, IgxGridPinningActionsComponent, IgxGridToolbarActionsComponent, IgxGridToolbarComponent, IgxGridToolbarHidingComponent, IgxGridToolbarPinningComponent } from 'igniteui-angular'; +import { ColumnPinningPosition, GridSelectionMode, IgxActionStripComponent, IgxButtonDirective, IgxButtonGroupComponent, IgxColumnComponent, IgxColumnLayoutComponent, IgxGridComponent, IgxGridEditingActionsComponent, IgxGridPinningActionsComponent, IgxGridToolbarActionsComponent, IgxGridToolbarComponent, IgxGridToolbarHidingComponent, IgxGridToolbarPinningComponent } from 'igniteui-angular'; @Component({ @@ -15,6 +15,8 @@ export class GridMRLSampleComponent { @ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true }) private grid: IgxGridComponent; + public pinPos = ColumnPinningPosition.End; + public width = null; public cols: Array = [ { field: 'ID', rowStart: 1, colStart: 1}, diff --git a/src/app/hierarchical-grid-add-row/hierarchical-grid-add-row.sample.html b/src/app/hierarchical-grid-add-row/hierarchical-grid-add-row.sample.html index c5544724b72..8a74b80b056 100644 --- a/src/app/hierarchical-grid-add-row/hierarchical-grid-add-row.sample.html +++ b/src/app/hierarchical-grid-add-row/hierarchical-grid-add-row.sample.html @@ -1,15 +1,22 @@ + [rowEditable]="true" + (columnInit)="columnInit($event)"> + + + + + + - - diff --git a/src/app/hierarchical-grid-add-row/hierarchical-grid-add-row.sample.ts b/src/app/hierarchical-grid-add-row/hierarchical-grid-add-row.sample.ts index b410f8a24ed..b4d4f7e6f6b 100644 --- a/src/app/hierarchical-grid-add-row/hierarchical-grid-add-row.sample.ts +++ b/src/app/hierarchical-grid-add-row/hierarchical-grid-add-row.sample.ts @@ -1,10 +1,11 @@ import { Component, ChangeDetectorRef, AfterViewInit } from '@angular/core'; -import { IgxActionStripComponent, IgxGridEditingActionsComponent, IgxGridPinningActionsComponent, IgxHierarchicalGridComponent, IgxRowIslandComponent } from 'igniteui-angular'; +import { ColumnPinningPosition, IColumnsAutoGeneratedEventArgs, IgxActionStripComponent, IgxColumnComponent, IgxGridEditingActionsComponent, IgxGridPinningActionsComponent, IgxGridToolbarActionsComponent, IgxGridToolbarComponent, IgxGridToolbarHidingComponent, IgxGridToolbarPinningComponent, IgxHierarchicalGridComponent, IgxRowIslandComponent } from 'igniteui-angular'; @Component({ selector: 'app-hierarchical-grid-add-row-sample', templateUrl: 'hierarchical-grid-add-row.sample.html', - imports: [IgxHierarchicalGridComponent, IgxActionStripComponent, IgxGridPinningActionsComponent, IgxGridEditingActionsComponent, IgxRowIslandComponent] + imports: [IgxHierarchicalGridComponent, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, + IgxGridToolbarPinningComponent, IgxGridToolbarHidingComponent, IgxActionStripComponent, IgxGridPinningActionsComponent, IgxGridEditingActionsComponent, IgxRowIslandComponent] }) export class HierarchicalGridAddRowSampleComponent implements AfterViewInit { public localData = []; @@ -23,6 +24,18 @@ export class HierarchicalGridAddRowSampleComponent implements AfterViewInit { this.cdr.detectChanges(); } + public columnInit(e: IgxColumnComponent) { + if(e.field === 'ID') { + e.pinningPosition = ColumnPinningPosition.End; + e.pinned = true; + } + + if(e.field === 'ProductName') { + e.pinningPosition = ColumnPinningPosition.Start; + e.pinned = true; + } + } + public generateDataUneven(count: number, level: number, parendID: string = null) { const prods = []; const currLevel = level; diff --git a/src/app/tree-grid/tree-grid.sample.html b/src/app/tree-grid/tree-grid.sample.html index 364a0a14454..e5c0fbda7c9 100644 --- a/src/app/tree-grid/tree-grid.sample.html +++ b/src/app/tree-grid/tree-grid.sample.html @@ -3,7 +3,7 @@ - diff --git a/src/app/tree-grid/tree-grid.sample.ts b/src/app/tree-grid/tree-grid.sample.ts index 5fe222208f8..44989f7d246 100644 --- a/src/app/tree-grid/tree-grid.sample.ts +++ b/src/app/tree-grid/tree-grid.sample.ts @@ -3,7 +3,7 @@ import { FormsModule } from '@angular/forms'; import { HIERARCHICAL_SAMPLE_DATA } from '../shared/sample-data'; import { GridSearchBoxComponent } from '../grid-search-box/grid-search-box.component'; -import { IgxButtonGroupComponent, IgxTreeGridComponent, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxGridToolbarHidingComponent, IgxGridToolbarAdvancedFilteringComponent, IgxGridToolbarExporterComponent, IgxExcelTextDirective, IgxCSVTextDirective, IgxPaginatorComponent, IgxSwitchComponent, IgxButtonDirective, IgxToggleActionDirective, IgxDropDownItemNavigationDirective, IgxDropDownComponent, IgxDropDownItemComponent, GridSelectionMode, TreeGridFilteringStrategy, IgxExcelExporterService, IgxCsvExporterService, IgxExcelExporterOptions, IgxCsvExporterOptions, CsvFileTypes } from 'igniteui-angular'; +import { IgxButtonGroupComponent, IgxTreeGridComponent, IgxGridToolbarComponent, IgxGridToolbarActionsComponent, IgxGridToolbarPinningComponent, IgxGridToolbarHidingComponent, IgxGridToolbarAdvancedFilteringComponent, IgxGridToolbarExporterComponent, IgxExcelTextDirective, IgxCSVTextDirective, IgxPaginatorComponent, IgxSwitchComponent, IgxButtonDirective, IgxToggleActionDirective, IgxDropDownItemNavigationDirective, IgxDropDownComponent, IgxDropDownItemComponent, GridSelectionMode, TreeGridFilteringStrategy, IgxExcelExporterService, IgxCsvExporterService, IgxExcelExporterOptions, IgxCsvExporterOptions, CsvFileTypes, IgxColumnComponent, ColumnPinningPosition } from 'igniteui-angular'; @Component({ @@ -36,6 +36,18 @@ export class TreeGridSampleComponent implements OnInit { } + public columnInit(e: IgxColumnComponent) { + if(e.field === 'ID') { + e.pinningPosition = ColumnPinningPosition.End; + e.pinned = true; + } + + if(e.field === 'CompanyName') { + e.pinningPosition = ColumnPinningPosition.Start; + e.pinned = true; + } + } + public ngOnInit(): void { this.selectionMode = GridSelectionMode.multiple; this.sizes = [