@catull/igniteui-angular
Version:
Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps
1,438 lines • 181 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { AfterContentInit, ChangeDetectorRef, ChangeDetectionStrategy, Component, ContentChild, ContentChildren, Input, QueryList, TemplateRef, Output, EventEmitter, } from '@angular/core';
import { notifyChanges } from '../watch-changes';
import { WatchColumnChanges } from '../watch-changes';
import { IgxRowIslandAPIService } from '../hierarchical-grid/row-island-api.service';
import { DataType } from '../../data-operations/data-util';
import { DeprecateProperty } from '../../core/deprecateDecorators';
import { IgxFilteringOperand, IgxBooleanFilteringOperand, IgxNumberFilteringOperand, IgxDateFilteringOperand, IgxStringFilteringOperand } from '../../data-operations/filtering-condition';
import { DefaultSortingStrategy } from '../../data-operations/sorting-strategy';
import { DisplayDensity } from '../../core/displayDensity';
import { IgxRowDirective } from '../row.directive';
import { GridBaseAPIService } from '../api.service';
import { getNodeSizeViaRange } from '../../core/utils';
import { IgxSummaryOperand, IgxNumberSummaryOperand, IgxDateSummaryOperand } from '../summaries/grid-summary';
import { IgxCellTemplateDirective, IgxCellHeaderTemplateDirective, IgxCellEditorTemplateDirective, IgxCollapsibleIndicatorTemplateDirective, IgxFilterCellTemplateDirective } from './templates.directive';
/**
* **Ignite UI for Angular Column** -
* [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid.html#columns-configuration)
*
* The Ignite UI Column is used within an `igx-grid` element to define what data the column will show. Features such as sorting,
* filtering & editing are enabled at the column level. You can also provide a template containing custom content inside
* the column using `ng-template` which will be used for all cells within the column.
*/
let IgxColumnComponent = class IgxColumnComponent {
constructor(gridAPI, cdr, rowIslandAPI) {
this.gridAPI = gridAPI;
this.cdr = cdr;
this.rowIslandAPI = rowIslandAPI;
/**
* Sets/gets the `header` value.
* ```typescript
* let columnHeader = this.column.header;
* ```
* ```html
* <igx-column [header] = "'ID'"></igx-column>
* ```
*
* @memberof IgxColumnComponent
*/
this.header = '';
/**
* Sets/gets whether the column is sortable.
* Default value is `false`.
* ```typescript
* let isSortable = this.column.sortable;
* ```
* ```html
* <igx-column [sortable] = "true"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.sortable = false;
/**
* Sets/gets whether the column is groupable.
* Default value is `false`.
* ```typescript
* let isGroupable = this.column.groupable;
* ```
* ```html
* <igx-column [groupable] = "true"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.groupable = false;
/**
* Sets/gets whether the column is filterable.
* Default value is `true`.
* ```typescript
* let isFilterable = this.column.filterable;
* ```
* ```html
* <igx-column [filterable] = "false"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.filterable = true;
/**
* Sets/gets whether the column is resizable.
* Default value is `false`.
* ```typescript
* let isResizable = this.column.resizable;
* ```
* ```html
* <igx-column [resizable] = "true"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.resizable = false;
/**
*@hidden
*/
this.hiddenChange = new EventEmitter();
/** @hidden */
this.expandedChange = new EventEmitter();
/** @hidden */
this.collapsibleChange = new EventEmitter();
/** @hidden */
this.visibleWhenCollapsedChange = new EventEmitter();
/**
* Gets whether the hiding is disabled.
* ```typescript
* let isHidingDisabled = this.column.disableHiding;
* ```
* @memberof IgxColumnComponent
*/
this.disableHiding = false;
/**
* Gets whether the pinning is disabled.
* ```typescript
* let isPinningDisabled = this.column.disablePinning;
* ```
* @memberof IgxColumnComponent
*/
this.disablePinning = false;
/**
* Sets/gets whether the column is movable.
* Default value is `false`.
* ```typescript
* let isMovable = this.column.movable;
* ```
* ```html
* <igx-column [movable] = "true"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.movable = false;
/**
*@hidden
*/
this.widthChange = new EventEmitter();
this._calcWidth = null;
/**
* Sets/gets the class selector of the column header.
* ```typescript
* let columnHeaderClass = this.column.headerClasses;
* ```
* ```html
* <igx-column [headerClasses] = "'column-header'"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.headerClasses = '';
/**
* Sets/gets the class selector of the column group header.
* ```typescript
* let columnHeaderClass = this.column.headerGroupClasses;
* ```
* ```html
* <igx-column [headerGroupClasses] = "'column-group-header'"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.headerGroupClasses = '';
/**
* Sets conditional style properties on the column cells.
* Similar to `ngStyle` it accepts an object literal where the keys are
* the style properties and the value is the expression to be evaluated.
* As with `cellClasses` it accepts a callback function.
* ```typescript
* styles = {
* background: 'royalblue',
* color: (rowData, columnKey, cellValue, rowIndex) => value.startsWith('Important') : 'red': 'inherit'
* }
* ```
* ```html
* <igx-column [cellStyles]="styles"></igx-column>
* ```
*
* @memberof IgxColumnComponent
*/
this.cellStyles = null;
/**
* Sets/gets whether the column filtering should be case sensitive.
* Default value is `true`.
* ```typescript
* let filteringIgnoreCase = this.column.filteringIgnoreCase;
* ```
* ```html
* <igx-column [filteringIgnoreCase] = "false"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.filteringIgnoreCase = true;
/**
* Sets/gets whether the column sorting should be case sensitive.
* Default value is `true`.
* ```typescript
* let sortingIgnoreCase = this.column.sortingIgnoreCase;
* ```
* ```html
* <igx-column [sortingIgnoreCase] = "false"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.sortingIgnoreCase = true;
/**
* Sets/gets the data type of the column values.
* Default value is `string`.
* ```typescript
* let columnDataType = this.column.dataType;
* ```
* ```html
* <igx-column [dataType] = "'number'"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.dataType = DataType.String;
/**
*@hidden
*/
this.pinnedChange = new EventEmitter();
/**
* Sets/gets whether the column is `searchable`.
* Default value is `true`.
* ```typescript
* let isSearchable = this.column.searchable';
* ```
* ```html
* <igx-column [searchable] = "false"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
this.searchable = true;
/**
* @hidden
* @internal
*/
this.collapsible = false;
/**
* @hidden
* @internal
*/
this.expanded = true;
/**
* Sets/gets the parent column.
* ```typescript
* let parentColumn = this.column.parent;
* ```
* ```typescript
* this.column.parent = higherLevelColumn;
* ```
* @memberof IgxColumnComponent
*/
this.parent = null;
/**
*@hidden
*/
this._pinned = false;
/**
*@hidden
*/
this._summaries = null;
/**
*@hidden
*/
this._filters = null;
/**
*@hidden
*/
this._sortStrategy = DefaultSortingStrategy.instance();
/**
*@hidden
*/
this._hidden = false;
/**
*@hidden
*/
this._disablePinning = false;
/**
*@hidden
*/
this._defaultMinWidth = '';
/**
*@hidden
*/
this._hasSummary = false;
/**
* @hidden
*/
this._collapsible = false;
/**
* @hidden
*/
this._expanded = true;
this._vIndex = NaN;
}
/**
* Gets whether the column is editable.
* Default value is `false`.
* ```typescript
* let isEditable = this.column.editable;
* ```
* @memberof IgxColumnComponent
*/
get editable() {
// Updating the primary key when grid has transactions (incl. row edit)
// should not be allowed, as that can corrupt transaction state.
const rowEditable = this.grid && this.grid.rowEditable;
const hasTransactions = this.grid && this.grid.transactions.enabled;
if (this.isPrimaryColumn && (rowEditable || hasTransactions)) {
return false;
}
if (this._editable !== undefined) {
return this._editable;
}
else {
return rowEditable;
}
}
/**
* Sets whether the column is editable.
* ```typescript
* this.column.editable = true;
* ```
* ```html
* <igx-column [editable] = "true"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
set editable(editable) {
this._editable = editable;
}
/**
* Gets a value indicating whether the summary for the column is enabled.
* ```typescript
* let hasSummary = this.column.hasSummary;
* ```
* @memberof IgxColumnComponent
*/
get hasSummary() {
return this._hasSummary;
}
/**
* Sets a value indicating whether the summary for the column is enabled.
* Default value is `false`.
* ```html
* <igx-column [hasSummary] = "true"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
set hasSummary(value) {
this._hasSummary = value;
if (this.grid) {
this.grid.summaryService.resetSummaryHeight();
}
}
/**
* Gets whether the column is hidden.
* ```typescript
* let isHidden = this.column.hidden;
* ```
*@memberof IgxColumnComponent
*/
get hidden() {
return this._hidden;
}
/**
* Sets the column hidden property.
* Default value is `false`.
* ```html
* <igx-column [hidden] = "true"></igx-column>
* ```
*
* Two-way data binding.
* ```html
* <igx-column [(hidden)] = "model.isHidden"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
set hidden(value) {
if (this._hidden !== value) {
this._hidden = value;
this.hiddenChange.emit(this._hidden);
if (this.columnLayoutChild && this.parent.hidden !== value) {
this.parent.hidden = value;
return;
}
if (this.grid) {
this.grid.endEdit(false);
this.grid.summaryService.resetSummaryHeight();
this.grid.filteringService.refreshExpressions();
this.grid.notifyChanges();
}
}
}
/**
* Gets the `width` of the column.
* ```typescript
* let columnWidth = this.column.width;
* ```
* @memberof IgxColumnComponent
*/
get width() {
return this.widthSetByUser ? this._width : this.defaultWidth;
}
/**
* Sets the `width` of the column.
* ```html
* <igx-column [width] = "'25%'"></igx-column>
* ```
*
* Two-way data binding.
* ```html
* <igx-column [(width)]="model.columns[0].width"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
set width(value) {
if (value) {
this._calcWidth = null;
this.calcPixelWidth = NaN;
this.widthSetByUser = true;
// width could be passed as number from the template
// host bindings are not px affixed so we need to ensure we affix simple number strings
if (typeof (value) === 'number' || value.match(/^[0-9]*$/)) {
value = value + 'px';
}
this._width = value;
if (this.grid) {
this.cacheCalcWidth();
}
this.widthChange.emit(this._width);
}
}
/**
* @hidden
*/
get calcWidth() {
return this.getCalcWidth();
}
/**
* Sets/gets the minimum `width` of the column.
* Default value is `88`;
* ```typescript
* let columnMinWidth = this.column.minWidth;
* ```
* ```html
* <igx-column [minWidth] = "'15%'"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
set minWidth(value) {
const minVal = parseFloat(value);
if (Number.isNaN(minVal)) {
return;
}
this._defaultMinWidth = value;
}
get minWidth() {
return !this._defaultMinWidth ? this.defaultMinWidth : this._defaultMinWidth;
}
/**
* Gets the column index.
* ```typescript
* let columnIndex = this.column.index;
* ```
* @memberof IgxColumnComponent
*/
get index() {
return this.grid.columns.indexOf(this);
}
/**
* Gets whether the column is `pinned`.
* ```typescript
* let isPinned = this.column.pinned;
* ```
* @memberof IgxColumnComponent
*/
get pinned() {
return this._pinned;
}
/**
* Sets whether the column is pinned.
* Default value is `false`.
* ```html
* <igx-column [pinned] = "true"></igx-column>
* ```
*
* Two-way data binding.
* ```html
* <igx-column [(pinned)] = "model.columns[0].isPinned"></igx-column>
* ```
* @memberof IgxColumnComponent
*/
set pinned(value) {
if (this._pinned !== value) {
if (this.grid && this.width && !isNaN(parseInt(this.width, 10))) {
value ? this.pin() : this.unpin();
return;
}
/* No grid/width available at initialization. `initPinning` in the grid
will re-init the group (if present)
*/
this._unpinnedIndex = this.grid ? this.grid.columns.filter(x => !x.pinned).indexOf(this) : 0;
this._pinned = value;
this.pinnedChange.emit(this._pinned);
}
}
/**
* Gets the column `summaries`.
* ```typescript
* let columnSummaries = this.column.summaries;
* ```
* @memberof IgxColumnComponent
*/
get summaries() {
return this._summaries;
}
/**
* Sets the column `summaries`.
* ```typescript
* this.column.summaries = IgxNumberSummaryOperand;
* ```
* @memberof IgxColumnComponent
*/
set summaries(classRef) {
this._summaries = new classRef();
if (this.grid) {
this.grid.summaryService.removeSummariesCachePerColumn(this.field);
this.grid._summaryPipeTrigger++;
this.grid.summaryService.resetSummaryHeight();
}
}
/**
* Gets the column `filters`.
* ```typescript
* let columnFilters = this.column.filters'
* ```
* @memberof IgxColumnComponent
*/
get filters() {
return this._filters;
}
/**
* Sets the column `filters`.
* ```typescript
* this.column.filters = IgxBooleanFilteringOperand.instance().
* ```
* @memberof IgxColumnComponent
*/
set filters(instance) {
this._filters = instance;
}
/**
* Gets the column `sortStrategy`.
* ```typescript
* let sortStrategy = this.column.sortStrategy
* ```
* @memberof IgxColumnComponent
*/
get sortStrategy() {
return this._sortStrategy;
}
/**
* Sets the column `sortStrategy`.
* ```typescript
* this.column.sortStrategy = new CustomSortingStrategy().
* class CustomSortingStrategy extends SortingStrategy {...}
* ```
* @memberof IgxColumnComponent
*/
set sortStrategy(classRef) {
this._sortStrategy = classRef;
}
/**
* Gets the function that compares values for grouping.
* ```typescript
* let groupingComparer = this.column.groupingComparer'
* ```
* @memberof IgxColumnComponent
*/
get groupingComparer() {
return this._groupingComparer;
}
/**
* Sets a custom function to compare values for grouping.
* Subsequent values in the sorted data that the function returns 0 for are grouped.
* ```typescript
* this.column.groupingComparer = (a: any, b: any) => { return a === b ? 0 : -1; }
* ```
* @memberof IgxColumnComponent
*/
set groupingComparer(funcRef) {
this._groupingComparer = funcRef;
}
/**
* Gets the default minimum `width` of the column.
* ```typescript
* let defaultMinWidth = this.column.defaultMinWidth;
* ```
* @memberof IgxColumnComponent
*/
get defaultMinWidth() {
if (!this.grid) {
return '80';
}
switch (this.grid.displayDensity) {
case DisplayDensity.cosy:
return '64';
case DisplayDensity.compact:
return '56';
default:
return '80';
}
}
/**
* The reference to the `igx-grid` owner.
* ```typescript
* let gridComponent = this.column.grid;
* ```
* @memberof IgxColumnComponent
*/
get grid() {
return this.gridAPI.grid;
}
/**
* Returns a reference to the `bodyTemplate`.
* ```typescript
* let bodyTemplate = this.column.bodyTemplate;
* ```
* @memberof IgxColumnComponent
*/
get bodyTemplate() {
return this._bodyTemplate;
}
/**
* Sets the body template.
* ```html
* <ng-template #bodyTemplate igxCell let-val>
* <div style = "background-color: yellowgreen" (click) = "changeColor(val)">
* <span> {{val}} </span>
* </div>
* </ng-template>
* ```
* ```typescript
* @ViewChild("'bodyTemplate'", {read: TemplateRef })
* public bodyTemplate: TemplateRef<any>;
* this.column.bodyTemplate = this.bodyTemplate;
* ```
* @memberof IgxColumnComponent
*/
set bodyTemplate(template) {
this._bodyTemplate = template;
}
/**
* Returns a reference to the header template.
* ```typescript
* let headerTemplate = this.column.headerTemplate;
* ```
* @memberof IgxColumnComponent
*/
get headerTemplate() {
return this._headerTemplate;
}
/**
* Sets the header template.
* Note that the column header height is fixed and any content bigger than it will be cut off.
* ```html
* <ng-template #headerTemplate>
* <div style = "background-color:black" (click) = "changeColor(val)">
* <span style="color:red" >{{column.field}}</span>
* </div>
* </ng-template>
* ```
* ```typescript
* @ViewChild("'headerTemplate'", {read: TemplateRef })
* public headerTemplate: TemplateRef<any>;
* this.column.headerTemplate = this.headerTemplate;
* ```
* @memberof IgxColumnComponent
*/
set headerTemplate(template) {
this._headerTemplate = template;
}
/**
* Returns a reference to the inline editor template.
* ```typescript
* let inlineEditorTemplate = this.column.inlineEditorTemplate;
* ```
* @memberof IgxColumnComponent
*/
get inlineEditorTemplate() {
return this._inlineEditorTemplate;
}
/**
* Sets the inline editor template.
* ```html
* <ng-template #inlineEditorTemplate igxCellEditor let-cell="cell">
* <input type="string" [(ngModel)]="cell.value"/>
* </ng-template>
* ```
* ```typescript
* @ViewChild("'inlineEditorTemplate'", {read: TemplateRef })
* public inlineEditorTemplate: TemplateRef<any>;
* this.column.inlineEditorTemplate = this.inlineEditorTemplate;
* ```
* @memberof IgxColumnComponent
*/
set inlineEditorTemplate(template) {
this._inlineEditorTemplate = template;
}
/**
* Returns a reference to the `filterCellTemplate`.
* ```typescript
* let filterCellTemplate = this.column.filterCellTemplate;
* ```
* @memberof IgxColumnComponent
*/
get filterCellTemplate() {
return this._filterCellTemplate;
}
/**
* Sets the quick filter template.
* ```html
* <ng-template #filterCellTemplate IgxFilterCellTemplate let-column="column">
* <input (input)="onInput()">
* </ng-template>
* ```
* ```typescript
* @ViewChild("'filterCellTemplate'", {read: TemplateRef })
* public filterCellTemplate: TemplateRef<any>;
* this.column.filterCellTemplate = this.filterCellTemplate;
* ```
* @memberof IgxColumnComponent
*/
set filterCellTemplate(template) {
this._filterCellTemplate = template;
}
/**
* Gets the cells of the column.
* ```typescript
* let columnCells = this.column.cells;
* ```
* @memberof IgxColumnComponent
*/
get cells() {
return this.grid.rowList.filter((row) => row instanceof IgxRowDirective)
.map((row) => {
if (row.cells) {
return row.cells.filter((cell) => cell.columnIndex === this.index);
}
}).reduce((a, b) => a.concat(b), []);
}
/**
* Gets the column visible index.
* If the column is not visible, returns `-1`.
* ```typescript
* let visibleColumnIndex = this.column.visibleIndex;
* ```
* @memberof IgxColumnComponent
*/
get visibleIndex() {
if (!isNaN(this._vIndex)) {
return this._vIndex;
}
const unpinnedColumns = this.grid.unpinnedColumns.filter(c => !c.columnGroup);
const pinnedColumns = this.grid.pinnedColumns.filter(c => !c.columnGroup);
let col = this;
let vIndex = -1;
if (this.columnGroup) {
col = this.allChildren.filter(c => !c.columnGroup)[0];
}
if (this.columnLayoutChild) {
return this.parent.childrenVisibleIndexes.find(x => x.column === this).index;
}
if (!this.pinned) {
const indexInCollection = unpinnedColumns.indexOf(col);
vIndex = indexInCollection === -1 ? -1 : pinnedColumns.length + indexInCollection;
}
else {
vIndex = pinnedColumns.indexOf(col);
}
this._vIndex = vIndex;
return vIndex;
}
/**
* Returns a boolean indicating if the column is a `ColumnGroup`.
* ```typescript
* let columnGroup = this.column.columnGroup;
* ```
* @memberof IgxColumnComponent
*/
get columnGroup() {
return false;
}
/**
* Returns a boolean indicating if the column is a `ColumnLayout` for multi-row layout.
* ```typescript
* let columnGroup = this.column.columnGroup;
* ```
* @memberof IgxColumnComponent
*/
get columnLayout() {
return false;
}
/**
* Returns a boolean indicating if the column is a child of a `ColumnLayout` for multi-row layout.
* ```typescript
* let columnLayoutChild = this.column.columnLayoutChild;
* ```
* @memberof IgxColumnComponent
*/
get columnLayoutChild() {
return this.parent && this.parent.columnLayout;
}
/**
* Returns the children columns collection.
* Returns an empty array if the column does not contain children columns.
* ```typescript
* let childrenColumns = this.column.allChildren;
* ```
* @memberof IgxColumnComponent
*/
get allChildren() {
return [];
}
/**
* Returns the level of the column in a column group.
* Returns `0` if the column doesn't have a `parent`.
* ```typescript
* let columnLevel = this.column.level;
* ```
* @memberof IgxColumnComponent
*/
get level() {
let ptr = this.parent;
let lvl = 0;
while (ptr) {
lvl++;
ptr = ptr.parent;
}
return lvl;
}
get isLastPinned() {
return this.grid.pinnedColumns[this.grid.pinnedColumns.length - 1] === this;
}
get gridRowSpan() {
return this.rowEnd && this.rowStart ? this.rowEnd - this.rowStart : 1;
}
get gridColumnSpan() {
return this.colEnd && this.colStart ? this.colEnd - this.colStart : 1;
}
/**
* Indicates whether the column will be visible when its parent is collapsed.
* ```html
* <igx-column-group>
* <igx-column [visibleWhenCollapsed]="true"></igx-column>
* </igx-column-group>
* ```
* @memberof IgxColumnComponent
*/
set visibleWhenCollapsed(value) {
this._visibleWhenCollapsed = value;
this.visibleWhenCollapsedChange.emit(this._visibleWhenCollapsed);
if (this.parent) {
this.parent.setExpandCollapseState();
}
}
get visibleWhenCollapsed() {
return this._visibleWhenCollapsed;
}
/**
* Returns the filteringExpressionsTree of the column.
* ```typescript
* let tree = this.column.filteringExpressionsTree;
* ```
* @memberof IgxColumnComponent
*/
get filteringExpressionsTree() {
return this.grid.filteringExpressionsTree.find(this.field);
}
/**
* @hidden
*/
get isPrimaryColumn() {
return this.field !== undefined && this.grid !== undefined && this.field === this.grid.primaryKey;
}
/**
* @hidden
* @internal
*/
resetCaches() {
this._vIndex = NaN;
if (this.grid) {
this.cacheCalcWidth();
}
}
/**
*@hidden
*/
ngAfterContentInit() {
if (this.cellTemplate) {
this._bodyTemplate = this.cellTemplate.template;
}
if (this.headTemplate && this.headTemplate.length) {
this._headerTemplate = this.headTemplate.toArray()[0].template;
}
if (this.editorTemplate) {
this._inlineEditorTemplate = this.editorTemplate.template;
}
if (this.filterCellTemplateDirective) {
this._filterCellTemplate = this.filterCellTemplateDirective.template;
}
if (!this.summaries) {
switch (this.dataType) {
case DataType.String:
case DataType.Boolean:
this.summaries = IgxSummaryOperand;
break;
case DataType.Number:
this.summaries = IgxNumberSummaryOperand;
break;
case DataType.Date:
this.summaries = IgxDateSummaryOperand;
break;
default:
this.summaries = IgxSummaryOperand;
break;
}
}
if (!this.filters) {
switch (this.dataType) {
case DataType.Boolean:
this.filters = IgxBooleanFilteringOperand.instance();
break;
case DataType.Number:
this.filters = IgxNumberFilteringOperand.instance();
break;
case DataType.Date:
this.filters = IgxDateFilteringOperand.instance();
break;
case DataType.String:
default:
this.filters = IgxStringFilteringOperand.instance();
break;
}
}
}
/**
* @hidden
*/
getGridTemplate(isRow, isIE) {
if (isRow) {
const rowsCount = this.grid.multiRowLayoutRowSize;
return isIE ?
`(1fr)[${rowsCount}]` :
`repeat(${rowsCount},1fr)`;
}
else {
return this.getColumnSizesString(this.children);
}
}
getInitialChildColumnSizes(children) {
const columnSizes = [];
// find the smallest col spans
children.forEach(col => {
if (!col.colStart) {
return;
}
const newWidthSet = col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
const newSpanSmaller = columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].colSpan > col.gridColumnSpan;
const bothWidthsSet = col.widthSetByUser && columnSizes[col.colStart - 1] && columnSizes[col.colStart - 1].widthSetByUser;
const bothWidthsNotSet = !col.widthSetByUser && columnSizes[col.colStart - 1] && !columnSizes[col.colStart - 1].widthSetByUser;
if (columnSizes[col.colStart - 1] === undefined) {
// If nothing is defined yet take any column at first
// We use colEnd to know where the column actually ends, because not always it starts where we have it set in columnSizes.
columnSizes[col.colStart - 1] = {
ref: col,
width: col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
colSpan: col.gridColumnSpan,
colEnd: col.colStart + col.gridColumnSpan,
widthSetByUser: col.widthSetByUser
};
}
else if (newWidthSet || (newSpanSmaller && ((bothWidthsSet) || (bothWidthsNotSet)))) {
// If a column is set already it should either not have width defined or have width with bigger span than the new one.
/**
* If replaced column has bigger span, we want to fill the remaining columns
* that the replacing column does not fill with the old one.
**/
if (bothWidthsSet && newSpanSmaller) {
// Start from where the new column set would end and apply the old column to the rest depending on how much it spans.
// We have not yet replaced it so we can use it directly from the columnSizes collection.
// This is where colEnd is used because the colStart of the old column is not actually i + 1.
for (let i = col.colStart - 1 + col.gridColumnSpan; i < columnSizes[col.colStart - 1].colEnd - 1; i++) {
if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
columnSizes[i] = columnSizes[col.colStart - 1];
}
else {
break;
}
}
}
// Replace the old column with the new one.
columnSizes[col.colStart - 1] = {
ref: col,
width: col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
colSpan: col.gridColumnSpan,
colEnd: col.colStart + col.gridColumnSpan,
widthSetByUser: col.widthSetByUser
};
}
else if (bothWidthsSet && columnSizes[col.colStart - 1].colSpan < col.gridColumnSpan) {
// If the column already in the columnSizes has smaller span, we still need to fill any empty places with the current col.
// Start from where the smaller column set would end and apply the bigger column to the rest depending on how much it spans.
// Since here we do not have it in columnSizes we set it as a new column keeping the same colSpan.
for (let i = col.colStart - 1 + columnSizes[col.colStart - 1].colSpan; i < col.colStart - 1 + col.gridColumnSpan; i++) {
if (!columnSizes[i] || !columnSizes[i].widthSetByUser) {
columnSizes[i] = {
ref: col,
width: col.widthSetByUser || this.grid.columnWidthSetByUser ? parseInt(col.calcWidth, 10) : null,
colSpan: col.gridColumnSpan,
colEnd: col.colStart + col.gridColumnSpan,
widthSetByUser: col.widthSetByUser
};
}
else {
break;
}
}
}
});
// Flatten columnSizes so there are not columns with colSpan > 1
for (let i = 0; i < columnSizes.length; i++) {
if (columnSizes[i] && columnSizes[i].colSpan > 1) {
let j = 1;
// Replace all empty places depending on how much the current column spans starting from next col.
for (; j < columnSizes[i].colSpan && i + j + 1 < columnSizes[i].colEnd; j++) {
if (columnSizes[i + j] &&
((!columnSizes[i].width && columnSizes[i + j].width) ||
(!columnSizes[i].width && !columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan) ||
(!!columnSizes[i + j].width && columnSizes[i + j].colSpan <= columnSizes[i].colSpan))) {
// If we reach an already defined column that has width and the current doesn't have or
// if the reached column has bigger colSpan we stop.
break;
}
else {
const width = columnSizes[i].widthSetByUser ?
columnSizes[i].width / columnSizes[i].colSpan :
columnSizes[i].width;
columnSizes[i + j] = {
ref: columnSizes[i].ref,
width: width,
colSpan: 1,
colEnd: columnSizes[i].colEnd,
widthSetByUser: columnSizes[i].widthSetByUser
};
}
}
// Update the current column width so it is divided between all columns it spans and set it to 1.
columnSizes[i].width = columnSizes[i].widthSetByUser ?
columnSizes[i].width / columnSizes[i].colSpan :
columnSizes[i].width;
columnSizes[i].colSpan = 1;
// Update the index based on how much we have replaced. Subtract 1 because we started from 1.
i += j - 1;
}
}
return columnSizes;
}
getFilledChildColumnSizes(children) {
const columnSizes = this.getInitialChildColumnSizes(children);
// fill the gaps if there are any
const result = [];
for (let i = 0; i < columnSizes.length; i++) {
if (columnSizes[i] && !!columnSizes[i].width) {
result.push(columnSizes[i].width + 'px');
}
else {
result.push(parseInt(this.grid.getPossibleColumnWidth(), 10) + 'px');
}
}
return result;
}
getColumnSizesString(children) {
const res = this.getFilledChildColumnSizes(children);
return res.join(' ');
}
getResizableColUnderEnd() {
if (this.columnLayout || !this.columnLayoutChild || this.columnGroup) {
return [{ target: this, spanUsed: 1 }];
}
const columnSized = this.getInitialChildColumnSizes(this.parent.children);
const targets = [];
const colEnd = this.colEnd ? this.colEnd : this.colStart + 1;
for (let i = 0; i < columnSized.length; i++) {
if (this.colStart <= i + 1 && i + 1 < colEnd) {
targets.push({ target: columnSized[i].ref, spanUsed: 1 });
}
}
const targetsSquashed = [];
for (let j = 0; j < targets.length; j++) {
if (targetsSquashed.length && targetsSquashed[targetsSquashed.length - 1].target.field === targets[j].target.field) {
targetsSquashed[targetsSquashed.length - 1].spanUsed++;
}
else {
targetsSquashed.push(targets[j]);
}
}
return targetsSquashed;
}
/**
* Pins the column at the provided index in the pinned area. Defaults to index `0` if not provided.
* 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
*/
pin(index) {
// TODO: Probably should the return type of the old functions
// should be moved as a event parameter.
if (this.grid) {
this.grid.endEdit(true);
}
if (this._pinned) {
return false;
}
if (this.parent && !this.parent.pinned) {
return this.topLevelParent.pin(index);
}
const grid = this.grid;
const hasIndex = index !== undefined;
if (hasIndex && (index < 0 || index >= grid.pinnedColumns.length)) {
return false;
}
if (!this.parent && !this.pinnable) {
return false;
}
this._pinned = true;
this.pinnedChange.emit(this._pinned);
this._unpinnedIndex = grid._unpinnedColumns.indexOf(this);
index = index !== undefined ? index : grid._pinnedColumns.length;
const targetColumn = grid._pinnedColumns[index];
const args = { column: this, insertAtIndex: index, isPinned: true };
grid.onColumnPinning.emit(args);
if (grid._pinnedColumns.indexOf(this) === -1) {
grid._pinnedColumns.splice(args.insertAtIndex, 0, this);
if (grid._unpinnedColumns.indexOf(this) !== -1) {
grid._unpinnedColumns.splice(grid._unpinnedColumns.indexOf(this), 1);
}
}
if (hasIndex) {
grid._moveColumns(this, targetColumn);
}
if (this.columnGroup) {
this.allChildren.forEach(child => child.pin());
grid.reinitPinStates();
}
grid.resetCaches();
grid.notifyChanges();
if (this.columnLayoutChild) {
this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
}
this.grid.filteringService.refreshExpressions();
return true;
}
/**
* Unpins the column and place it at the provided index in the unpinned area. Defaults to index `0` if not provided.
* Returns `true` if the column is successfully unpinned. Returns `false` if the column cannot be unpinned.
* Column cannot be unpinned if:
* - Is already unpinned
* - index argument is out of range
* ```typescript
* let success = this.column.unpin();
* ```
* @memberof IgxColumnComponent
*/
unpin(index) {
if (this.grid) {
this.grid.endEdit(true);
}
if (!this._pinned) {
return false;
}
if (this.parent && this.parent.pinned) {
return this.topLevelParent.unpin(index);
}
const grid = this.grid;
const hasIndex = index !== undefined;
if (hasIndex && (index < 0 || index >= grid._unpinnedColumns.length)) {
return false;
}
index = (index !== undefined ? index :
this._unpinnedIndex !== undefined ? this._unpinnedIndex : this.index);
this._pinned = false;
this.pinnedChange.emit(this._pinned);
const targetColumn = grid._unpinnedColumns[index];
grid._unpinnedColumns.splice(index, 0, this);
if (grid._pinnedColumns.indexOf(this) !== -1) {
grid._pinnedColumns.splice(grid._pinnedColumns.indexOf(this), 1);
}
if (hasIndex) {
grid._moveColumns(this, targetColumn);
}
if (this.columnGroup) {
this.allChildren.forEach(child => child.unpin());
}
grid.reinitPinStates();
grid.resetCaches();
const insertAtIndex = grid._unpinnedColumns.indexOf(this);
const args = { column: this, insertAtIndex, isPinned: false };
grid.onColumnPinning.emit(args);
grid.notifyChanges();
if (this.columnLayoutChild) {
this.grid.columns.filter(x => x.columnLayout).forEach(x => x.populateVisibleIndexes());
}
this.grid.filteringService.refreshExpressions();
return true;
}
/**
* Returns a reference to the top level parent column.
* ```typescript
* let topLevelParent = this.column.topLevelParent;
* ```
* @memberof IgxColumnComponent
*/
get topLevelParent() {
let parent = this.parent;
while (parent && parent.parent) {
parent = parent.parent;
}
return parent;
}
/**
* Returns a reference to the header of the column.
* ```typescript
* let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
* let headerCell = column.headerCell;
* ```
* @memberof IgxColumnComponent
*/
get headerCell() {
return this.grid.headerCellList.find((header) => header.column === this);
}
/**
* Returns a reference to the filter cell of the column.
* ```typescript
* let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
* let filterell = column.filterell;
* ```
* @memberof IgxColumnComponent
*/
get filterCell() {
return this.grid.filterCellList.find((filterCell) => filterCell.column === this);
}
/**
* Returns a reference to the header group of the column.
* @memberof IgxColumnComponent
*/
get headerGroup() {
return this.grid.headerGroupsList.find((headerGroup) => headerGroup.column === this);
}
/**
* Autosize the column to the longest currently visible cell value, including the header cell.
* ```typescript
* @ViewChild('grid') grid: IgxGridComponent;
* let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
* column.autosize();
* ```
* @memberof IgxColumnComponent
*/
autosize() {
if (!this.columnGroup) {
this.width = this.getLargestCellWidth();
this.grid.reflow();
}
}
/**
* @hidden
*/
getCalcWidth() {
if (this._calcWidth !== null && !isNaN(this.calcPixelWidth)) {
return this._calcWidth;
}
this.cacheCalcWidth();
return this._calcWidth;
}
/**
* @hidden
* Returns the size (in pixels) of the longest currently visible cell, including the header cell.
* ```typescript
* @ViewChild('grid') grid: IgxGridComponent;
*
* let column = this.grid.columnList.filter(c => c.field === 'ID')[0];
* let size = column.getLargestCellWidth();
* ```
* @memberof IgxColumnComponent
*/
getLargestCellWidth() {
const range = this.grid.document.createRange();
const largest = new Map();
if (this.cells.length > 0) {
let cellsContentWidths = [];
if (this.cells[0].nativeElement.children.length > 0) {
this.cells.forEach((cell) => cellsContentWidths.push(cell.calculateSizeToFit(range)));
}
else {
cellsContentWidths = this.cells.map((cell) => getNodeSizeViaRange(range, cell.nativeElement));
}
const index = cellsContentWidths.indexOf(Math.max(...cellsContentWidths));
const cellStyle = this.grid.document.defaultView.getComputedStyle(this.cells[index].nativeElement);
const cellPadding = parseFloat(cellStyle.paddingLeft) + parseFloat(cellStyle.paddingRight) +
parseFloat(cellStyle.borderRightWidth);
largest.set(Math.max(...cellsContentWidths), cellPadding);
}
if (this.headerCell) {
let headerCell;
if (this.headerTemplate && this.headerCell.elementRef.nativeElement.children[0].children.length > 0) {
headerCell = Math.max(...Array.from(this.headerCell.elementRef.nativeElement.children[0].children)
.map((child) => getNodeSizeViaRange(range, child)));
}
else {
headerCell = getNodeSizeViaRange(range, this.headerCell.elementRef.nativeElement.children[0]);
}
if (this.sortable || this.filterable) {
headerCell += this.headerCell.elementRef.nativeElement.children[1].getBoundingClientRect().width;
}
const headerStyle = this.grid.document.defaultView.getComputedStyle(this.headerCell.elementRef.nativeElement);
const headerPadding = parseFloat(headerStyle.paddingLeft) + parseFloat(headerStyle.paddingRight) +
parseFloat(headerStyle.borderRightWidth);
largest.set(headerCell, headerPadding);
}
const largestCell = Math.max(...Array.from(largest.keys()));
const width = Math.ceil(largestCell + largest.get(largestCell));
if (Number.isNaN(width)) {
return this.width;
}
else {
return width + 'px';
}
}
/**
*@hidden
*/
getCellWidth() {
const colWidth = this.width;
const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
if (this.columnLayoutChild) {
return '';
}
if (colWidth && !isPercentageWidth) {
let cellWidth = colWidth;
if (typeof cellWidth !== 'string' || cellWidth.endsWith('px') === false) {
cellWidth += 'px';
}
return cellWidth;
}
else {
return colWidth;
}
}
/**
* @hidden
* @internal
*/
cacheCalcWidth() {
const grid = this.gridAPI.grid;
const colWidth = this.width;
const isPercentageWidth = colWidth && typeof colWidth === 'string' && colWidth.indexOf('%') !== -1;
if (isPercentageWidth) {
this._calcWidth = parseInt(colWidth, 10) / 100 * (grid.calcWidth - grid.featureColumnsWidth);
}
else if (!colWidth) {
// no width
this._calcWidth = this.defaultWidth || grid.getPossibleColumnWidth();
}
else {
this._calcWidth = this.width;
}
this.calcPixelWidth = parseInt(this._calcWidth, 10);
}
/**
* @hidden
* @internal
*/
setExpandCollapseState() {
this.children.filter(col => (col.visibleWhenCollapsed !== undefined)).forEach(c => {
if (!this.collapsible) {
c.hidden = this.hidden;
return;
}
c.hidden = this._expanded ? c.visibleWhenCollapsed : !c.visibleWhenCollapsed;
});
}
/**
* @hidden
* @internal
*/
checkCollapsibleState() {
if (!this.children) {
return false;
}
const cols = this.children.map(child => child.visibleWhenCollapsed);
return (cols.some(c => c === true) && cols.some(c => c === false));
}
/**
*@hidden
*/
get pinnable() {
return this.grid._init || !this.pinned;
}
/**
* @hidden
*/
populateVisibleIndexes() { }
};
IgxColumnComponent.ctorParameters = () => [
{ type: GridBaseAPIService },
{ type: ChangeDetectorRef },
{ type: IgxRowIslandAPIService }
];
__decorate([
Input(),
__metadata("design:type", String)
], IgxColumnComponent.prototype, "field", void 0);
__decorate([
notifyChanges(),
WatchColumnChanges(),
Input(),
__metadata("design:type", Object)
], IgxColumnComponent.prototype, "header", void 0);
__decorate([
WatchColumnChanges(),
Input(),
__metadata("design:type", Object)
], IgxColumnComponent.prototype, "sortable", void 0);
__decorate([
notifyChanges(true),
WatchColumnChanges(),
Input(),
__metadata("design:type", Object)
], IgxColumnComponent.prototype, "groupable", void 0);
__decorat