UNPKG

ag-grid

Version:

Advanced Data Grid / Data Table supporting Javascript / React / AngularJS / Web Components

685 lines (557 loc) 23.3 kB
import {ColumnGroupChild} from "./columnGroupChild"; import {OriginalColumnGroupChild} from "./originalColumnGroupChild"; import { AbstractColDef, BaseColDefParams, ColDef, ColSpanParams, IAggFunc, IsColumnFunc, IsColumnFuncParams, RowSpanParams } from "./colDef"; import {EventService} from "../eventService"; import {Utils as _} from "../utils"; import {Autowired, PostConstruct} from "../context/context"; import {GridOptionsWrapper} from "../gridOptionsWrapper"; import {ColumnUtils} from "../columnController/columnUtils"; import {RowNode} from "./rowNode"; import {IFrameworkFactory} from "../interfaces/iFrameworkFactory"; import {IEventEmitter} from "../interfaces/iEventEmitter"; import {ColumnEvent, ColumnEventType} from "../events"; import {ColumnApi} from "../columnController/columnApi"; import {GridApi} from "../gridApi"; import {ColumnGroup} from "./columnGroup"; // Wrapper around a user provide column definition. The grid treats the column definition as ready only. // This class contains all the runtime information about a column, plus some logic (the definition has no logic). // This class implements both interfaces ColumnGroupChild and OriginalColumnGroupChild as the class can // appear as a child of either the original tree or the displayed tree. However the relevant group classes // for each type only implements one, as each group can only appear in it's associated tree (eg OriginalColumnGroup // can only appear in OriginalColumn tree). export class Column implements ColumnGroupChild, OriginalColumnGroupChild, IEventEmitter { // + renderedHeaderCell - for making header cell transparent when moving public static EVENT_MOVING_CHANGED = 'movingChanged'; // + renderedCell - changing left position public static EVENT_LEFT_CHANGED = 'leftChanged'; // + renderedCell - changing width public static EVENT_WIDTH_CHANGED = 'widthChanged'; // + renderedCell - for changing pinned classes public static EVENT_LAST_LEFT_PINNED_CHANGED = 'lastLeftPinnedChanged'; public static EVENT_FIRST_RIGHT_PINNED_CHANGED = 'firstRightPinnedChanged'; // + renderedColumn - for changing visibility icon public static EVENT_VISIBLE_CHANGED = 'visibleChanged'; // + every time the filter changes, used in the floating filters public static EVENT_FILTER_CHANGED = 'filterChanged'; // + renderedHeaderCell - marks the header with filter icon public static EVENT_FILTER_ACTIVE_CHANGED = 'filterActiveChanged'; // + renderedHeaderCell - marks the header with sort icon public static EVENT_SORT_CHANGED = 'sortChanged'; public static EVENT_MENU_VISIBLE_CHANGED = 'menuVisibleChanged'; // + toolpanel, for gui updates public static EVENT_ROW_GROUP_CHANGED = 'columnRowGroupChanged'; // + toolpanel, for gui updates public static EVENT_PIVOT_CHANGED = 'columnPivotChanged'; // + toolpanel, for gui updates public static EVENT_VALUE_CHANGED = 'columnValueChanged'; public static PINNED_RIGHT = 'right'; public static PINNED_LEFT = 'left'; public static SORT_ASC = 'asc'; public static SORT_DESC = 'desc'; @Autowired('gridOptionsWrapper') private gridOptionsWrapper: GridOptionsWrapper; @Autowired('columnUtils') private columnUtils: ColumnUtils; @Autowired('frameworkFactory') private frameworkFactory: IFrameworkFactory; @Autowired('columnApi') private columnApi: ColumnApi; @Autowired('gridApi') private gridApi: GridApi; private colDef: ColDef; private colId: any; private actualWidth: any; private visible: any; private pinned: string; private left: number; private oldLeft: number; private aggFunc: string | IAggFunc; private sort: string; private sortedAt: number; private moving = false; private menuVisible = false; // we copy this from col def, as if it's value changes are column is created, // it will break the logic in the column controller private lockPosition: boolean; private lockPinned: boolean; private lockVisible: boolean; private lastLeftPinned: boolean; private firstRightPinned: boolean; private minWidth: number; private maxWidth: number; private filterActive = false; private eventService: EventService = new EventService(); private fieldContainsDots: boolean; private tooltipFieldContainsDots: boolean; private rowGroupActive = false; private pivotActive = false; private aggregationActive = false; private primary: boolean; private parent: ColumnGroup; constructor(colDef: ColDef, colId: String, primary: boolean) { this.colDef = colDef; this.visible = !colDef.hide; this.sort = colDef.sort; this.sortedAt = colDef.sortedAt; this.colId = colId; this.primary = primary; this.lockPosition = colDef.lockPosition === true; this.lockPinned = colDef.lockPinned === true; this.lockVisible = colDef.lockVisible === true; } public isLockPosition(): boolean { return this.lockPosition; } public isLockVisible(): boolean { return this.lockVisible; } public isLockPinned(): boolean { return this.lockPinned; } public setParent(parent: ColumnGroup): void { this.parent = parent; } public getParent(): ColumnGroup { return this.parent; } // this is done after constructor as it uses gridOptionsWrapper @PostConstruct public initialise(): void { this.setPinned(this.colDef.pinned); let minColWidth = this.gridOptionsWrapper.getMinColWidth(); let maxColWidth = this.gridOptionsWrapper.getMaxColWidth(); if (this.colDef.minWidth) { this.minWidth = this.colDef.minWidth; } else { this.minWidth = minColWidth; } if (this.colDef.maxWidth) { this.maxWidth = this.colDef.maxWidth; } else { this.maxWidth = maxColWidth; } this.actualWidth = this.columnUtils.calculateColInitialWidth(this.colDef); let suppressDotNotation = this.gridOptionsWrapper.isSuppressFieldDotNotation(); this.fieldContainsDots = _.exists(this.colDef.field) && this.colDef.field.indexOf('.')>=0 && !suppressDotNotation; this.tooltipFieldContainsDots = _.exists(this.colDef.tooltipField) && this.colDef.tooltipField.indexOf('.')>=0 && !suppressDotNotation; this.validate(); } public isEmptyGroup(): boolean { return false; } public isRowGroupDisplayed(colId: string): boolean { if (_.missing(this.colDef) || _.missing(this.colDef.showRowGroup)) { return false; } let showingAllGroups = this.colDef.showRowGroup === true; let showingThisGroup = this.colDef.showRowGroup === colId; return showingAllGroups || showingThisGroup; } public getUniqueId(): string { return this.getId(); } public isPrimary(): boolean { return this.primary; } public isFilterAllowed(): boolean { return this.primary && !this.colDef.suppressFilter; } public isFieldContainsDots(): boolean { return this.fieldContainsDots; } public isTooltipFieldContainsDots(): boolean { return this.tooltipFieldContainsDots; } private validate(): void { let colDefAny = <any> this.colDef; if (!this.gridOptionsWrapper.isEnterprise()) { let itemsNotAllowedWithoutEnterprise = ['enableRowGroup','rowGroup','rowGroupIndex','enablePivot','pivot','pivotIndex','aggFunc']; itemsNotAllowedWithoutEnterprise.forEach( item => { if (_.exists(colDefAny[item])) { console.warn(`ag-Grid: ${item} is only valid in ag-Grid-Enterprise, your column definition should not have ${item}`); } }); } if (this.gridOptionsWrapper.isTreeData()) { let itemsNotAllowedWithTreeData = ['enableRowGroup','rowGroup','rowGroupIndex','enablePivot','pivot','pivotIndex']; itemsNotAllowedWithTreeData.forEach( item => { if (_.exists(colDefAny[item])) { console.warn(`ag-Grid: ${item} is not possible when doing tree data, your column definition should not have ${item}`); } }); } if (_.exists(this.colDef.width) && typeof this.colDef.width !== 'number') { console.warn('ag-Grid: colDef.width should be a number, not ' + typeof this.colDef.width); } if (_.get(this, 'colDef.cellRendererParams.restrictToOneGroup', null)) { console.warn('ag-Grid: Since ag-grid 11.0.0 cellRendererParams.restrictToOneGroup is deprecated. You should use showRowGroup'); } if (_.get(this, 'colDef.cellRendererParams.keyMap', null)) { console.warn('ag-Grid: Since ag-grid 11.0.0 cellRendererParams.keyMap is deprecated. You should use colDef.keyCreator'); } if (_.get(this, 'colDef.cellRendererParams.keyMap', null)) { console.warn('ag-Grid: Since ag-grid 11.0.0 cellRendererParams.keyMap is deprecated. You should use colDef.keyCreator'); } if (colDefAny.floatingCellRenderer) { console.warn('ag-Grid: since v11, floatingCellRenderer is now pinnedRowCellRenderer'); this.colDef.pinnedRowCellRenderer = colDefAny.floatingCellRenderer; } if (colDefAny.floatingRendererFramework) { console.warn('ag-Grid: since v11, floatingRendererFramework is now pinnedRowCellRendererFramework'); this.colDef.pinnedRowCellRendererFramework = colDefAny.floatingRendererFramework; } if (colDefAny.floatingRendererParams) { console.warn('ag-Grid: since v11, floatingRendererParams is now pinnedRowCellRendererParams'); this.colDef.pinnedRowCellRendererParams = colDefAny.floatingRendererParams; } if (colDefAny.floatingValueFormatter) { console.warn('ag-Grid: since v11, floatingValueFormatter is now pinnedRowValueFormatter'); this.colDef.pinnedRowValueFormatter = colDefAny.floatingValueFormatter; } if (colDefAny.cellFormatter) { console.warn('ag-Grid: since v12, cellFormatter is now valueFormatter'); if (_.missing(this.colDef.valueFormatter)) { this.colDef.valueFormatter = colDefAny.cellFormatter; } } if (colDefAny.headerCellTemplate) { console.warn('ag-Grid: since v15, headerCellTemplate is gone, use header component instead.'); } if (colDefAny.headerCellRenderer) { console.warn('ag-Grid: since v15, headerCellRenderer is gone, use header component instead.'); } if (colDefAny.volatile) { console.warn('ag-Grid: since v16, colDef.volatile is gone, please check refresh docs on how to refresh specific cells.'); } } public addEventListener(eventType: string, listener: Function): void { this.eventService.addEventListener(eventType, listener); } public removeEventListener(eventType: string, listener: Function): void { this.eventService.removeEventListener(eventType, listener); } private createIsColumnFuncParams(rowNode: RowNode): IsColumnFuncParams { return { node: rowNode, data: rowNode.data, column: this, colDef: this.colDef, context: this.gridOptionsWrapper.getContext(), api: this.gridOptionsWrapper.getApi(), columnApi: this.gridOptionsWrapper.getColumnApi() }; } public isSuppressNavigable(rowNode: RowNode): boolean { // if boolean set, then just use it if (typeof this.colDef.suppressNavigable === 'boolean') { return <boolean> this.colDef.suppressNavigable; } // if function, then call the function to find out if (typeof this.colDef.suppressNavigable === 'function') { let params = this.createIsColumnFuncParams(rowNode); let userFunc = <IsColumnFunc> this.colDef.suppressNavigable; return userFunc(params); } return false; } public isCellEditable(rowNode: RowNode): boolean { // only allow editing of groups if the user has this option enabled if (rowNode.group && !this.gridOptionsWrapper.isEnableGroupEdit()) { return false; } return this.isColumnFunc(rowNode, this.colDef.editable); } public isRowDrag(rowNode: RowNode): boolean { return this.isColumnFunc(rowNode, this.colDef.rowDrag); } public isCellCheckboxSelection(rowNode: RowNode): boolean { return this.isColumnFunc(rowNode, this.colDef.checkboxSelection); } public isSuppressPaste(rowNode: RowNode): boolean { return this.isColumnFunc(rowNode, this.colDef ? this.colDef.suppressPaste : null); } public isResizable(): boolean { let enableColResize = this.gridOptionsWrapper.isEnableColResize(); let suppressResize = this.colDef && this.colDef.suppressResize; return enableColResize && !suppressResize; } private isColumnFunc(rowNode: RowNode, value: boolean | IsColumnFunc): boolean { // if boolean set, then just use it if (typeof value === 'boolean') { return <boolean> value; } // if function, then call the function to find out if (typeof value === 'function') { let params = this.createIsColumnFuncParams(rowNode); let editableFunc = <IsColumnFunc> value; return editableFunc(params); } return false; } public setMoving(moving: boolean, source: ColumnEventType = "api"): void { this.moving = moving; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_MOVING_CHANGED, source)); } private createColumnEvent(type: string, source: ColumnEventType): ColumnEvent { return { api: this.gridApi, columnApi: this.columnApi, type: type, column: this, columns: [this], source: source }; } public isMoving(): boolean { return this.moving; } public getSort(): string { return this.sort; } public setSort(sort: string, source: ColumnEventType = "api"): void { if (this.sort !== sort) { this.sort = sort; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_SORT_CHANGED, source)); } } public setMenuVisible(visible: boolean, source: ColumnEventType = "api"): void { if (this.menuVisible !== visible) { this.menuVisible = visible; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_MENU_VISIBLE_CHANGED, source)); } } public isMenuVisible(): boolean { return this.menuVisible; } public isSortAscending(): boolean { return this.sort === Column.SORT_ASC; } public isSortDescending(): boolean { return this.sort === Column.SORT_DESC; } public isSortNone(): boolean { return _.missing(this.sort); } public isSorting(): boolean { return _.exists(this.sort); } public getSortedAt(): number { return this.sortedAt; } public setSortedAt(sortedAt: number): void { this.sortedAt = sortedAt; } public setAggFunc(aggFunc: string | IAggFunc): void { this.aggFunc = aggFunc; } public getAggFunc(): string | IAggFunc { return this.aggFunc; } public getLeft(): number { return this.left; } public getOldLeft(): number { return this.oldLeft; } public getRight(): number { return this.left + this.actualWidth; } public setLeft(left: number, source: ColumnEventType = "api") { this.oldLeft = this.left; if (this.left !== left) { this.left = left; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_LEFT_CHANGED, source)); } } public isFilterActive(): boolean { return this.filterActive; } public setFilterActive(active: boolean, source: ColumnEventType = "api"): void { if (this.filterActive !== active) { this.filterActive = active; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_FILTER_ACTIVE_CHANGED, source)); } this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_FILTER_CHANGED, source)); } public setPinned(pinned: string|boolean): void { if (pinned===true || pinned===Column.PINNED_LEFT) { this.pinned = Column.PINNED_LEFT; } else if (pinned===Column.PINNED_RIGHT) { this.pinned = Column.PINNED_RIGHT; } else { this.pinned = null; } } public setFirstRightPinned(firstRightPinned: boolean, source: ColumnEventType = "api"): void { if (this.firstRightPinned !== firstRightPinned) { this.firstRightPinned = firstRightPinned; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_FIRST_RIGHT_PINNED_CHANGED, source)); } } public setLastLeftPinned(lastLeftPinned: boolean, source: ColumnEventType = "api"): void { if (this.lastLeftPinned !== lastLeftPinned) { this.lastLeftPinned = lastLeftPinned; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_LAST_LEFT_PINNED_CHANGED, source)); } } public isFirstRightPinned(): boolean { return this.firstRightPinned; } public isLastLeftPinned(): boolean { return this.lastLeftPinned; } public isPinned(): boolean { return this.pinned === Column.PINNED_LEFT || this.pinned === Column.PINNED_RIGHT; } public isPinnedLeft(): boolean { return this.pinned === Column.PINNED_LEFT; } public isPinnedRight(): boolean { return this.pinned === Column.PINNED_RIGHT; } public getPinned(): string { return this.pinned; } public setVisible(visible: boolean, source: ColumnEventType = "api"): void { let newValue = visible===true; if (this.visible !== newValue) { this.visible = newValue; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_VISIBLE_CHANGED, source)); } } public isVisible(): boolean { return this.visible; } public getColDef(): ColDef { return this.colDef; } public getColumnGroupShow(): string { return this.colDef.columnGroupShow; } public getColId(): string { return this.colId; } public getId(): string { return this.getColId(); } public getDefinition(): AbstractColDef { return this.colDef; } public getActualWidth(): number { return this.actualWidth; } private createBaseColDefParams(rowNode: RowNode): BaseColDefParams { let params: BaseColDefParams = { node: rowNode, data: rowNode.data, colDef: this.colDef, column: this, api: this.gridOptionsWrapper.getApi(), columnApi: this.gridOptionsWrapper.getColumnApi(), context: this.gridOptionsWrapper.getContext() }; return params; } public getColSpan(rowNode: RowNode): number { if (_.missing(this.colDef.colSpan)) { return 1; } else { let params: ColSpanParams = this.createBaseColDefParams(rowNode); let colSpan = this.colDef.colSpan(params); // colSpan must be number equal to or greater than 1 if (colSpan > 1) { return colSpan; } else { return 1; } } } public getRowSpan(rowNode: RowNode): number { if (_.missing(this.colDef.rowSpan)) { return 1; } else { let params: RowSpanParams = this.createBaseColDefParams(rowNode); let rowSpan = this.colDef.rowSpan(params); // rowSpan must be number equal to or greater than 1 if (rowSpan > 1) { return rowSpan; } else { return 1; } } } public setActualWidth(actualWidth: number, source: ColumnEventType = "api"): void { if (this.actualWidth !== actualWidth) { this.actualWidth = actualWidth; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_WIDTH_CHANGED, source)); } } public isGreaterThanMax(width: number): boolean { if (this.maxWidth) { return width > this.maxWidth; } else { return false; } } public getMinWidth(): number { return this.minWidth; } public getMaxWidth(): number { return this.maxWidth; } public setMinimum(source: ColumnEventType = "api"): void { this.setActualWidth(this.minWidth, source); } public setRowGroupActive(rowGroup: boolean, source: ColumnEventType = "api"): void { if (this.rowGroupActive !== rowGroup) { this.rowGroupActive = rowGroup; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_ROW_GROUP_CHANGED, source)); } } public isRowGroupActive(): boolean { return this.rowGroupActive; } public setPivotActive(pivot: boolean, source: ColumnEventType = "api"): void { if (this.pivotActive !== pivot) { this.pivotActive = pivot; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_PIVOT_CHANGED, source)); } } public isPivotActive(): boolean { return this.pivotActive; } public isAnyFunctionActive(): boolean { return this.isPivotActive() || this.isRowGroupActive() || this.isValueActive(); } public isAnyFunctionAllowed(): boolean { return this.isAllowPivot() || this.isAllowRowGroup() || this.isAllowValue(); } public setValueActive(value: boolean, source: ColumnEventType = "api"): void { if (this.aggregationActive !== value) { this.aggregationActive = value; this.eventService.dispatchEvent(this.createColumnEvent(Column.EVENT_VALUE_CHANGED, source)); } } public isValueActive(): boolean { return this.aggregationActive; } public isAllowPivot(): boolean { return this.colDef.enablePivot === true; } public isAllowValue(): boolean { return this.colDef.enableValue === true; } public isAllowRowGroup(): boolean { return this.colDef.enableRowGroup === true; } public getMenuTabs(defaultValues: string[]): string [] { let menuTabs: string[] = this.getColDef().menuTabs; if (menuTabs == null) { menuTabs = defaultValues; } return menuTabs; } }