UNPKG

igniteui-angular-sovn

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

1,707 lines (1,513 loc) 71 kB
import { AfterContentInit, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, ElementRef, HostBinding, Inject, Input, IterableDiffers, LOCALE_ID, NgZone, OnInit, Output, Optional, QueryList, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, Injector, ApplicationRef, ContentChild, createComponent, EnvironmentInjector, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { DOCUMENT, NgTemplateOutlet, NgIf, NgClass, NgStyle, NgFor } from '@angular/common'; import { IgxGridBaseDirective } from '../grid-base.directive'; import { IgxFilteringService } from '../filtering/grid-filtering.service'; import { IgxGridSelectionService } from '../selection/selection.service'; import { IgxForOfSyncService, IgxForOfScrollSyncService } from '../../directives/for-of/for_of.sync.service'; import { ColumnType, GridType, IGX_GRID_BASE, RowType } from '../common/grid.interface'; import { IgxGridCRUDService } from '../common/crud.service'; import { IgxGridSummaryService } from '../summaries/grid-summary.service'; import { DEFAULT_PIVOT_KEYS, IDimensionsChange, IgxPivotGridValueTemplateContext, IPivotConfiguration, IPivotConfigurationChangedEventArgs, IPivotDimension, IPivotValue, IValuesChange, PivotDimensionType } from './pivot-grid.interface'; import { IgxPivotHeaderRowComponent } from './pivot-header-row.component'; import { IgxColumnGroupComponent } from '../columns/column-group.component'; import { IgxColumnComponent } from '../columns/column.component'; import { PivotUtil } from './pivot-util'; import { FilterMode, GridPagingMode, GridSummaryCalculationMode, GridSummaryPosition } from '../common/enums'; import { WatchChanges } from '../watch-changes'; import { OverlaySettings } from '../../services/public_api'; import { ICellPosition, IColumnMovingEndEventArgs, IColumnMovingEventArgs, IColumnMovingStartEventArgs, IColumnVisibilityChangedEventArgs, IGridEditDoneEventArgs, IGridEditEventArgs, IGridToolbarExportEventArgs, IPinColumnCancellableEventArgs, IPinColumnEventArgs, IPinRowEventArgs, IRowDataEventArgs, IRowDragEndEventArgs, IRowDragStartEventArgs } from '../common/events'; import { IgxGridRowComponent } from '../grid/grid-row.component'; import { DropPosition } from '../moving/moving.service'; import { DimensionValuesFilteringStrategy, NoopPivotDimensionsStrategy } from '../../data-operations/pivot-strategy'; import { IgxGridExcelStyleFilteringComponent, IgxExcelStyleColumnOperationsTemplateDirective, IgxExcelStyleFilterOperationsTemplateDirective } from '../filtering/excel-style/excel-style-filtering.component'; import { IgxPivotGridNavigationService } from './pivot-grid-navigation.service'; import { IgxPivotColumnResizingService } from '../resizing/pivot-grid/pivot-resizing.service'; import { IgxFlatTransactionFactory, IgxOverlayService, State, Transaction, TransactionService } from '../../services/public_api'; import { DisplayDensity, DisplayDensityToken, IDensityChangedEventArgs, IDisplayDensityOptions } from '../../core/density'; import { cloneArray, PlatformUtil } from '../../core/utils'; import { IgxPivotFilteringService } from './pivot-filtering.service'; import { DataUtil } from '../../data-operations/data-util'; import { IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; import { IgxGridTransaction } from '../common/types'; import { GridBaseAPIService } from '../api.service'; import { IgxGridForOfDirective } from '../../directives/for-of/for_of.directive'; import { IgxPivotRowDimensionContentComponent } from './pivot-row-dimension-content.component'; import { IgxPivotGridColumnResizerComponent } from '../resizing/pivot-grid/pivot-resizer.component'; import { IgxActionStripComponent } from '../../action-strip/action-strip.component'; import { ISortingExpression, SortingDirection } from '../../data-operations/sorting-strategy'; import { PivotSortUtil } from './pivot-sort-util'; import { IFilteringStrategy } from '../../data-operations/filtering-strategy'; import { IgxPivotValueChipTemplateDirective } from './pivot-grid.directives'; import { IFilteringOperation } from '../../data-operations/filtering-condition'; import { IgxGridValidationService } from '../grid/grid-validation.service'; import { IgxPivotRowPipe, IgxPivotRowExpansionPipe, IgxPivotAutoTransform, IgxPivotColumnPipe, IgxPivotGridFilterPipe, IgxPivotGridSortingPipe, IgxPivotGridColumnSortingPipe, IgxPivotCellMergingPipe } from './pivot-grid.pipes'; import { IgxGridRowClassesPipe, IgxGridRowStylesPipe } from '../common/pipes'; import { IgxExcelStyleSearchComponent } from '../filtering/excel-style/excel-style-search.component'; import { IgxIconComponent } from '../../icon/icon.component'; import { IgxSnackbarComponent } from '../../snackbar/snackbar.component'; import { IgxCircularProgressBarComponent } from '../../progressbar/progressbar.component'; import { IgxToggleDirective, IgxOverlayOutletDirective } from '../../directives/toggle/toggle.directive'; import { IgxPivotRowComponent } from './pivot-row.component'; import { IgxTemplateOutletDirective } from '../../directives/template-outlet/template_outlet.directive'; import { IgxColumnMovingDropDirective } from '../moving/moving.drop.directive'; import { IgxGridDragSelectDirective } from '../selection/drag-select.directive'; import { IgxGridBodyDirective } from '../grid.common'; import { IgxColumnResizingService } from '../resizing/resizing.service'; import { DefaultDataCloneStrategy, IDataCloneStrategy } from '../../data-operations/data-clone-strategy'; let NEXT_ID = 0; const MINIMUM_COLUMN_WIDTH = 200; const MINIMUM_COLUMN_WIDTH_SUPER_COMPACT = 104; /** * Pivot Grid provides a way to present and manipulate data in a pivot table view. * * @igxModule IgxPivotGridModule * @igxGroup Grids & Lists * @igxKeywords pivot, grid, table * @igxTheme igx-grid-theme * @remarks * The Ignite UI Pivot Grid is used for grouping and aggregating simple flat data into a pivot table. Once data * has been bound and the dimensions and values configured it can be manipulated via sorting and filtering. * @example * ```html * <igx-pivot-grid [data]="data" [pivotConfiguration]="configuration"> * </igx-pivot-grid> * ``` */ @Component({ changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, selector: 'igx-pivot-grid', templateUrl: 'pivot-grid.component.html', providers: [ IgxGridCRUDService, IgxGridValidationService, IgxGridSummaryService, IgxGridSelectionService, IgxColumnResizingService, GridBaseAPIService, { provide: IGX_GRID_BASE, useExisting: IgxPivotGridComponent }, { provide: IgxFilteringService, useClass: IgxPivotFilteringService }, IgxPivotGridNavigationService, IgxPivotColumnResizingService, IgxForOfSyncService, IgxForOfScrollSyncService ], standalone: true, imports: [ NgIf, NgFor, NgClass, NgStyle, NgTemplateOutlet, IgxPivotHeaderRowComponent, IgxGridBodyDirective, IgxGridDragSelectDirective, IgxColumnMovingDropDirective, IgxGridForOfDirective, IgxTemplateOutletDirective, IgxPivotRowComponent, IgxToggleDirective, IgxCircularProgressBarComponent, IgxSnackbarComponent, IgxOverlayOutletDirective, IgxPivotGridColumnResizerComponent, IgxIconComponent, IgxPivotRowDimensionContentComponent, IgxGridExcelStyleFilteringComponent, IgxExcelStyleColumnOperationsTemplateDirective, IgxExcelStyleFilterOperationsTemplateDirective, IgxExcelStyleSearchComponent, IgxGridRowClassesPipe, IgxGridRowStylesPipe, IgxPivotRowPipe, IgxPivotRowExpansionPipe, IgxPivotAutoTransform, IgxPivotColumnPipe, IgxPivotGridFilterPipe, IgxPivotGridSortingPipe, IgxPivotGridColumnSortingPipe, IgxPivotCellMergingPipe ], schemas: [ CUSTOM_ELEMENTS_SCHEMA ] }) export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnInit, AfterContentInit, GridType, AfterViewInit { /** * Emitted when the dimension collection is changed via the grid chip area. * * @remarks * Returns the new dimension collection and its type: * @example * ```html * <igx-pivot-grid #grid [data]="localData" [height]="'305px'" * (dimensionsChange)="dimensionsChange($event)"></igx-grid> * ``` */ @Output() public dimensionsChange = new EventEmitter<IDimensionsChange>(); /** * Emitted when any of the pivotConfiguration properties is changed via the grid chip area. * * @example * ```html * <igx-pivot-grid #grid [data]="localData" [height]="'305px'" * (pivotConfigurationChanged)="configurationChanged($event)"></igx-grid> * ``` */ @Output() public pivotConfigurationChange = new EventEmitter<IPivotConfigurationChangedEventArgs>(); /** * Emitted when the dimension is initialized. * @remarks * Emits the dimension that is about to be initialized. * @example * ```html * <igx-pivot-grid #grid [data]="localData" [height]="'305px'" * (dimensionInit)="dimensionInit($event)"></igx-pivot-grid> * ``` */ @Output() public dimensionInit = new EventEmitter<IPivotDimension>(); /** * Emitted when the value is initialized. * @remarks * Emits the value that is about to be initialized. * @example * ```html * <igx-pivot-grid #grid [data]="localData" [height]="'305px'" * (valueInit)="valueInit($event)"></igx-pivot-grid> * ``` */ @Output() public valueInit = new EventEmitter<IPivotValue>(); /** * Emitted when a dimension is sorted. * * @example * ```html * <igx-pivot-grid #grid [data]="localData" [height]="'305px'" * (dimensionsSortingExpressionsChange)="dimensionsSortingExpressionsChange($event)"></igx-pivot-grid> * ``` */ @Output() public dimensionsSortingExpressionsChange = new EventEmitter<ISortingExpression[]>(); /** * Emitted when the values collection is changed via the grid chip area. * * @remarks * Returns the new dimension * @example * ```html * <igx-pivot-grid #grid [data]="localData" [height]="'305px'" * (valuesChange)="valuesChange($event)"></igx-grid> * ``` */ @Output() public valuesChange = new EventEmitter<IValuesChange>(); /** * Gets the sorting expressions generated for the dimensions. * * @example * ```typescript * const expressions = this.grid.dimensionsSortingExpressions; * ``` */ public get dimensionsSortingExpressions() { const allEnabledDimensions = this.rowDimensions.concat(this.columnDimensions); const dimensionsSortingExpressions = PivotSortUtil.generateDimensionSortingExpressions(allEnabledDimensions); return dimensionsSortingExpressions; } /** @hidden @internal */ @ViewChild(IgxPivotHeaderRowComponent, { static: true }) public override theadRow: IgxPivotHeaderRowComponent; /** * @hidden @internal */ @ContentChild(IgxPivotValueChipTemplateDirective, { read: IgxPivotValueChipTemplateDirective }) protected valueChipTemplateDirective: IgxPivotValueChipTemplateDirective; /** * Gets/Sets a custom template for the value chips. * * @example * ```html * <igx-pivot-grid [valueChipTemplate]="myTemplate"><igx-pivot-grid> * ``` */ @Input() public valueChipTemplate: TemplateRef<IgxPivotGridValueTemplateContext>; @Input() /** * Gets/Sets the pivot configuration with all related dimensions and values. * * @example * ```html * <igx-pivot-grid [pivotConfiguration]="config"></igx-pivot-grid> * ``` */ public set pivotConfiguration(value: IPivotConfiguration) { this._pivotConfiguration = value; this.emitInitEvents(this._pivotConfiguration); this.filteringExpressionsTree = PivotUtil.buildExpressionTree(value); if (!this._init) { this.setupColumns(); } this.notifyChanges(true); } public get pivotConfiguration() { return this._pivotConfiguration || { rows: null, columns: null, values: null, filters: null }; } @Input() /** * Gets/Sets the pivot configuration ui for the pivot grid - chips and their * corresponding containers for row, filter, column dimensions and values * * @example * ```html * <igx-pivot-grid [showPivotConfigurationUI]="false"></igx-pivot-grid> * ``` */ public showPivotConfigurationUI = true; /** * @hidden @internal */ @HostBinding('attr.role') public role = 'grid'; /** * Enables a super compact theme for the component. * @remarks * Overrides the displayDensity option if one is set. * @example * ```html * <igx-pivot-grid [superCompactMode]="true"></igx-pivot-grid> * ``` */ @HostBinding('class.igx-grid__pivot--super-compact') @Input() public get superCompactMode() { return this._superCompactMode; } public set superCompactMode(value) { Promise.resolve().then(() => { // wait for the current detection cycle to end before triggering a new one. this._superCompactMode = value; this.cdr.detectChanges(); }); } /** * Returns the theme of the component. * The default theme is `comfortable`. * Available options are `comfortable`, `cosy`, `compact`. * @remarks * If set while superCompactMode is enabled will have no affect. * ```typescript * let componentTheme = this.component.displayDensity; * ``` */ @Input() public override get displayDensity(): DisplayDensity { if (this.superCompactMode) { return DisplayDensity.compact; } return super.displayDensity; } /** * Sets the theme of the component. */ public override set displayDensity(val: DisplayDensity) { const currentDisplayDensity = this._displayDensity; this._displayDensity = val as DisplayDensity; if (currentDisplayDensity !== this._displayDensity) { const densityChangedArgs: IDensityChangedEventArgs = { oldDensity: currentDisplayDensity, newDensity: this._displayDensity }; this.densityChanged.emit(densityChangedArgs); } } /** * Gets/Sets the values clone strategy of the pivot grid when assigning them to different dimensions. * * @example * ```html * <igx-pivot-grid #grid [data]="localData" [pivotValueCloneStrategy]="customCloneStrategy"></igx-pivot-grid> * ``` * @hidden @internal */ @Input() public get pivotValueCloneStrategy(): IDataCloneStrategy { return this._pivotValueCloneStrategy; } public set pivotValueCloneStrategy(strategy: IDataCloneStrategy) { if (strategy) { this._pivotValueCloneStrategy = strategy; } } /** * @hidden @internal */ @ViewChild('record_template', { read: TemplateRef, static: true }) public recordTemplate: TemplateRef<any>; /** * @hidden @internal */ @ViewChild('headerTemplate', { read: TemplateRef, static: true }) public headerTemplate: TemplateRef<any>; /** * @hidden @internal */ @ViewChild(IgxPivotGridColumnResizerComponent) public override resizeLine: IgxPivotGridColumnResizerComponent; /** * @hidden @internal */ @ViewChildren(IgxGridExcelStyleFilteringComponent, { read: IgxGridExcelStyleFilteringComponent }) public override excelStyleFilteringComponents: QueryList<IgxGridExcelStyleFilteringComponent>; /** * @hidden @internal */ @ViewChildren(IgxPivotRowDimensionContentComponent) protected rowDimensionContentCollection: QueryList<IgxPivotRowDimensionContentComponent>; /** * @hidden @internal */ protected override get minColumnWidth() { if (this.superCompactMode) { return MINIMUM_COLUMN_WIDTH_SUPER_COMPACT; } else { return MINIMUM_COLUMN_WIDTH; } } /** * @hidden @internal */ @ViewChildren('verticalRowDimScrollContainer', { read: IgxGridForOfDirective }) public verticalRowDimScrollContainers: QueryList<IgxGridForOfDirective<any, any[]>>; /** * @hidden @internal */ @Input() public override addRowEmptyTemplate: TemplateRef<void>; /** * @hidden @internal */ @Input() public override autoGenerateExclude: string[] = []; /** * @hidden @internal */ @Input() public override snackbarDisplayTime = 6000; /** * @hidden @internal */ @Output() public override cellEdit = new EventEmitter<IGridEditEventArgs>(); /** * @hidden @internal */ @Output() public override cellEditDone = new EventEmitter<IGridEditDoneEventArgs>(); /** * @hidden @internal */ @Output() public override cellEditEnter = new EventEmitter<IGridEditEventArgs>(); /** * @hidden @internal */ @Output() public override cellEditExit = new EventEmitter<IGridEditDoneEventArgs>(); /** * @hidden @internal */ @Output() public override columnMovingStart = new EventEmitter<IColumnMovingStartEventArgs>(); /** * @hidden @internal */ @Output() public override columnMoving = new EventEmitter<IColumnMovingEventArgs>(); /** * @hidden @internal */ @Output() public override columnMovingEnd = new EventEmitter<IColumnMovingEndEventArgs>(); /** * @hidden @internal */ @Output() public override columnPin = new EventEmitter<IPinColumnCancellableEventArgs>(); /** * @hidden @internal */ @Output() public override columnPinned = new EventEmitter<IPinColumnEventArgs>(); /** * @hidden @internal */ @Output() public override rowAdd = new EventEmitter<IGridEditEventArgs>(); /** * @hidden @internal */ @Output() public override rowAdded = new EventEmitter<IRowDataEventArgs>(); /** * @hidden @internal */ @Output() public override rowDeleted = new EventEmitter<IRowDataEventArgs>(); /** * @hidden @internal */ @Output() public override rowDelete = new EventEmitter<IGridEditEventArgs>(); /** * @hidden @internal */ @Output() public override rowDragStart = new EventEmitter<IRowDragStartEventArgs>(); /** * @hidden @internal */ @Output() public override rowDragEnd = new EventEmitter<IRowDragEndEventArgs>(); /** * @hidden @internal */ @Output() public override rowEditEnter = new EventEmitter<IGridEditEventArgs>(); /** * @hidden @internal */ @Output() public override rowEdit = new EventEmitter<IGridEditEventArgs>(); /** * @hidden @internal */ @Output() public override rowEditDone = new EventEmitter<IGridEditDoneEventArgs>(); /** * @hidden @internal */ @Output() public override rowEditExit = new EventEmitter<IGridEditDoneEventArgs>(); /** * @hidden @internal */ @Output() public override rowPinning = new EventEmitter<IPinRowEventArgs>(); /** * @hidden @internal */ @Output() public override rowPinned = new EventEmitter<IPinRowEventArgs>(); /** @hidden @internal */ public columnGroupStates = new Map<string, boolean>(); /** @hidden @internal */ public dimensionDataColumns; /** @hidden @internal */ public get pivotKeys() { return this.pivotConfiguration.pivotKeys || DEFAULT_PIVOT_KEYS; } /** @hidden @internal */ public override isPivot = true; /** * @hidden @internal */ public override dragRowID = null; /** * @hidden @internal */ public override get rootSummariesEnabled(): boolean { return false; } /** * @hidden @internal */ public rowDimensionResizing = true; private _emptyRowDimension: IPivotDimension = { memberName: '', enabled: true, level: 0 }; /** * @hidden @internal */ public get emptyRowDimension(): IPivotDimension { return this._emptyRowDimension; } protected _pivotValueCloneStrategy: IDataCloneStrategy = new DefaultDataCloneStrategy(); protected override _defaultExpandState = false; protected override _filterStrategy: IFilteringStrategy = new DimensionValuesFilteringStrategy(); private _data; private _pivotConfiguration: IPivotConfiguration = { rows: null, columns: null, values: null, filters: null }; private p_id = `igx-pivot-grid-${NEXT_ID++}`; private _superCompactMode = false; /** * Gets/Sets the default expand state for all rows. */ @Input() public get defaultExpandState() { return this._defaultExpandState; } public set defaultExpandState(val: boolean) { this._defaultExpandState = val; } /** * @hidden @internal */ @Input() public override get pagingMode() { return; } public override set pagingMode(_val: GridPagingMode) { } /** * @hidden @internal */ @WatchChanges() @Input() public override get hideRowSelectors() { return; } public override set hideRowSelectors(_value: boolean) { } /** * @hidden @internal */ public override autoGenerate = true; /** * @hidden @internal */ public override actionStrip: IgxActionStripComponent; /** * @hidden @internal */ public override shouldGenerate: boolean; /** * @hidden @internal */ public override moving = false; /** * @hidden @internal */ public override toolbarExporting = new EventEmitter<IGridToolbarExportEventArgs>(); /** * @hidden @internal */ @Input() public override get rowDraggable(): boolean { return; } public override set rowDraggable(_val: boolean) { } /** * @hidden @internal */ @Input() public override get allowAdvancedFiltering() { return false; } public override set allowAdvancedFiltering(_value) { } /** * @hidden @internal */ @Input() public override get filterMode() { return FilterMode.quickFilter; } public override set filterMode(_value: FilterMode) { } /** * @hidden @internal */ @Input() public override get allowFiltering() { return false; } public override set allowFiltering(_value) { } /** * @hidden @internal */ @Input() public override get page(): number { return 0; } public override set page(_val: number) { } /** * @hidden @internal */ @Input() public override get perPage(): number { return; } public override set perPage(_val: number) { } /** * @hidden @internal */ public override get pinnedColumns(): IgxColumnComponent[] { return []; } /** * @hidden @internal */ public override get unpinnedColumns(): IgxColumnComponent[] { return super.unpinnedColumns; } /** * @hidden @internal */ public override get unpinnedDataView(): any[] { return super.unpinnedDataView; } /** * @hidden @internal */ public override get unpinnedWidth() { return super.unpinnedWidth; } /** * @hidden @internal */ public override get pinnedWidth() { return super.pinnedWidth; } /** * @hidden @internal */ @Input() public override set summaryRowHeight(_value: number) { } public override get summaryRowHeight(): number { return 0; } /** * @hidden @internal */ public override get transactions(): TransactionService<Transaction, State> { return this._transactions; } /** * @hidden @internal */ public override get dragIndicatorIconTemplate(): TemplateRef<any> { return; } public override set dragIndicatorIconTemplate(_val: TemplateRef<any>) { } /** * @hidden @internal */ @WatchChanges() @Input() public override get rowEditable(): boolean { return; } public override set rowEditable(_val: boolean) { } /** * @hidden @internal */ @Input() public override get pinning() { return {}; } public override set pinning(_value) { } /** * @hidden @internal */ @Input() public override get summaryPosition() { return; } public override set summaryPosition(_value: GridSummaryPosition) { } /** * @hidden @interal */ @Input() public override get summaryCalculationMode() { return; } public override set summaryCalculationMode(_value: GridSummaryCalculationMode) { } /** * @hidden @interal */ @Input() public override get showSummaryOnCollapse() { return; } public override set showSummaryOnCollapse(_value: boolean) { } /** * @hidden @internal */ public override get hiddenColumnsCount() { return null; } /** * @hidden @internal */ public override get pinnedColumnsCount() { return null; } /** * @hidden @internal */ @Input() public override get batchEditing(): boolean { return; } public override set batchEditing(_val: boolean) { } public override get selectedRows(): any[] { if (this.selectionService.getSelectedRows().length === 0) { return []; } const selectedRowIds = []; this.dataView.forEach(record => { const prev = []; for (const dim of this.rowDimensions) { let currDim = dim; let shouldBreak = false; do { const key = PivotUtil.getRecordKey(record, currDim); if (this.selectionService.isPivotRowSelected(key) && !selectedRowIds.find(x => x === record)) { selectedRowIds.push(record); shouldBreak = true; break; } currDim = currDim.childLevel; } while (currDim); prev.push(dim); if (shouldBreak) { break; } } }); return selectedRowIds; } /** * Gets the default row height. * * @example * ```typescript * const rowHeigh = this.grid.defaultRowHeight; * ``` */ public override get defaultRowHeight(): number { if (this.superCompactMode) { return 24; } return super.defaultRowHeight; } constructor( validationService: IgxGridValidationService, selectionService: IgxGridSelectionService, colResizingService: IgxPivotColumnResizingService, gridAPI: GridBaseAPIService<IgxGridBaseDirective & GridType>, transactionFactory: IgxFlatTransactionFactory, elementRef: ElementRef<HTMLElement>, zone: NgZone, @Inject(DOCUMENT) document, cdr: ChangeDetectorRef, differs: IterableDiffers, viewRef: ViewContainerRef, appRef: ApplicationRef, injector: Injector, envInjector: EnvironmentInjector, navigation: IgxPivotGridNavigationService, filteringService: IgxFilteringService, @Inject(IgxOverlayService) overlayService: IgxOverlayService, summaryService: IgxGridSummaryService, @Optional() @Inject(DisplayDensityToken) _displayDensityOptions: IDisplayDensityOptions, @Inject(LOCALE_ID) localeId: string, platform: PlatformUtil, @Optional() @Inject(IgxGridTransaction) _diTransactions?: TransactionService<Transaction, State>) { super( validationService, selectionService, colResizingService, gridAPI, transactionFactory, elementRef, zone, document, cdr, differs, viewRef, appRef, injector, envInjector, navigation, filteringService, overlayService, summaryService, _displayDensityOptions, localeId, platform, _diTransactions); } /** * @hidden */ public override ngOnInit() { // pivot grid always generates columns automatically. this.autoGenerate = true; super.ngOnInit(); } /** * @hidden */ public override ngAfterContentInit() { // ignore any user defined columns and auto-generate based on pivot config. this.updateColumns([]); Promise.resolve().then(() => { this.setupColumns(); }); if (this.valueChipTemplateDirective) { this.valueChipTemplate = this.valueChipTemplateDirective.template; } } /** * @hidden @internal */ public override ngAfterViewInit() { Promise.resolve().then(() => { super.ngAfterViewInit(); }); } /** * Notifies for dimension change. */ public notifyDimensionChange(regenerateColumns = false) { if (regenerateColumns) { this.setupColumns(); } this.pipeTrigger++; this.cdr.detectChanges(); } /** * Gets the full list of dimensions. * * @example * ```typescript * const dimensions = this.grid.allDimensions; * ``` */ public get allDimensions() { const config = this._pivotConfiguration; if (!config) return []; return (config.rows || []).concat((config.columns || [])).concat(config.filters || []).filter(x => x !== null && x !== undefined); } /** @hidden @internal */ public createFilterESF(dropdown: any, column: ColumnType, options: OverlaySettings, shouldReatach: boolean) { options.outlet = this.outlet; if (dropdown) { dropdown.initialize(column, this.overlayService); if (shouldReatach) { const id = this.overlayService.attach(dropdown.element, options); dropdown.overlayComponentId = id; return { id, ref: undefined }; } return { id: dropdown.overlayComponentId, ref: undefined }; } } /** @hidden */ public override featureColumnsWidth() { return this.pivotRowWidths; } /** * Gets/Sets the value of the `id` attribute. * * @remarks * If not provided it will be automatically generated. * @example * ```html * <igx-pivot-grid [id]="'igx-pivot-1'" [data]="Data"></igx-pivot-grid> * ``` */ @HostBinding('attr.id') @Input() public get id(): string { return this.p_id; } public set id(value: string) { this.p_id = value; } /** * An @Input property that lets you fill the `IgxPivotGridComponent` with an array of data. * ```html * <igx-pivot-grid [data]="Data"></igx-pivot-grid> * ``` */ @Input() public set data(value: any[] | null) { this._data = value || []; if (!this._init) { this.setupColumns(); this.reflow(); } this.cdr.markForCheck(); if (this.height === null || this.height.indexOf('%') !== -1) { // If the height will change based on how much data there is, recalculate sizes in igxForOf. this.notifyChanges(true); } } /** * Returns an array of data set to the component. * ```typescript * let data = this.grid.data; * ``` */ public get data(): any[] | null { return this._data; } /** * @hidden */ public getContext(rowData, rowIndex): any { return { $implicit: rowData, templateID: { type: 'dataRow', id: null }, index: this.getDataViewIndex(rowIndex, false) }; } /** * @hidden @internal */ public get pivotRowWidths() { return this.rowDimensions.length ? this.rowDimensions.reduce((accumulator, dim) => accumulator + this.rowDimensionWidthToPixels(dim), 0) : this.rowDimensionWidthToPixels(this.emptyRowDimension); } /** * @hidden @internal */ public rowDimensionWidthToPixels(dim: IPivotDimension, ignoreBeforeInit = false): number { if (!ignoreBeforeInit && this.shouldGenerate) { return 0; } if (!dim.width) { return MINIMUM_COLUMN_WIDTH; } const isPercent = dim.width && dim.width.indexOf('%') !== -1; if (isPercent) { return parseFloat(dim.width) / 100 * this.calcWidth; } else { return parseInt(dim.width, 10); } } /** * @hidden @internal */ public reverseDimensionWidthToPercent(width: number): number { return (width * 100 / this.calcWidth); } /** @hidden @internal */ public get pivotContentCalcWidth() { const totalDimWidth = this.rowDimensions.length > 0 ? this.rowDimensions.map((dim) => this.rowDimensionWidthToPixels(dim)).reduce((prev, cur) => prev + cur) : 0; return this.calcWidth - totalDimWidth; } /** @hidden @internal */ public get pivotPinnedWidth() { return !this.shouldGenerate ? (this.isPinningToStart ? this.pinnedWidth : this.headerFeaturesWidth) : 0; } /** @hidden @internal */ public get pivotUnpinnedWidth() { return !this.shouldGenerate ? this.unpinnedWidth : 0; } /** @hidden @internal */ public get rowDimensions() { return this.pivotConfiguration.rows?.filter(x => x.enabled) || []; } /** @hidden @internal */ public get columnDimensions() { return this.pivotConfiguration.columns?.filter(x => x.enabled) || []; } /** @hidden @internal */ public get filterDimensions() { return this.pivotConfiguration.filters?.filter(x => x.enabled) || []; } /** @hidden @internal */ public get values() { return this.pivotConfiguration.values?.filter(x => x.enabled) || []; } public toggleColumn(col: IgxColumnComponent) { const state = this.columnGroupStates.get(col.field); const newState = !state; this.columnGroupStates.set(col.field, newState); this.toggleRowGroup(col, newState); this.reflow(); } protected override getColumnWidthSum(): number { let colSum = super.getColumnWidthSum(); colSum += this.rowDimensions.map(dim => this.rowDimensionWidthToPixels(dim, true)).reduce((prev, cur) => prev + cur, 0); return colSum; } /** * @hidden @internal */ public override isRecordPinnedByIndex(_rowIndex: number) { return null; } /** * @hidden @internal */ public override toggleColumnVisibility(_args: IColumnVisibilityChangedEventArgs) { return; } /** * @hidden @internal */ public override expandAll() { } /** * @hidden @internal */ public override collapseAll() { } /** * @hidden @internal */ public override expandRow(_rowID: any) { } /** * @hidden @internal */ public override collapseRow(_rowID: any) { } /** * @hidden @internal */ public override get pinnedRows(): IgxGridRowComponent[] { return; } /** * @hidden @internal */ @Input() public override get totalRecords(): number { return; } public override set totalRecords(_total: number) { } /** * @hidden @internal */ public override moveColumn(_column: IgxColumnComponent, _target: IgxColumnComponent, _pos: DropPosition = DropPosition.AfterDropTarget) { } /** * @hidden @internal */ public override addRow(_data: any): void { } /** * @hidden @internal */ public override deleteRow(_rowSelector: any): any { } /** * @hidden @internal */ public override updateCell(_value: any, _rowSelector: any, _column: string): void { } /** * @hidden @internal */ public override updateRow(_value: any, _rowSelector: any): void { } /** * @hidden @internal */ public override enableSummaries(..._rest) { } /** * @hidden @internal */ public override disableSummaries(..._rest) { } /** * @hidden @internal */ public override pinColumn(_columnName: string | IgxColumnComponent, _index?): boolean { return; } /** * @hidden @internal */ public override unpinColumn(_columnName: string | IgxColumnComponent, _index?): boolean { return; } /** * @hidden @internal */ public override pinRow(_rowID: any, _index?: number, _row?: RowType): boolean { return; } /** * @hidden @internal */ public override unpinRow(_rowID: any, _row?: RowType): boolean { return; } /** * @hidden @internal */ public override get pinnedRowHeight() { return; } /** * @hidden @internal */ public override get hasEditableColumns(): boolean { return; } /** * @hidden @internal */ public override get hasSummarizedColumns(): boolean { return; } /** * @hidden @internal */ public override get hasMovableColumns(): boolean { return; } /** * @hidden @internal */ public override get pinnedDataView(): any[] { return []; } /** * @hidden @internal */ public override openAdvancedFilteringDialog(_overlaySettings?: OverlaySettings) { } /** * @hidden @internal */ public override closeAdvancedFilteringDialog(_applyChanges: boolean) { } /** * @hidden @internal */ public override endEdit(_commit = true, _event?: Event) { } /** * @hidden @internal */ public override beginAddRowById(_rowID: any, _asChild?: boolean): void { } /** * @hidden @internal */ public override beginAddRowByIndex(_index: number): void { } /** * @hidden @internal */ public override clearSearch() { } /** * @hidden @internal */ public override refreshSearch(_updateActiveInfo?: boolean, _endEdit = true): number { return 0; } /** * @hidden @internal */ public override findNext(_text: string, _caseSensitive?: boolean, _exactMatch?: boolean): number { return 0; } /** * @hidden @internal */ public override findPrev(_text: string, _caseSensitive?: boolean, _exactMatch?: boolean): number { return 0; } /** * @hidden @internal */ public override getNextCell(currRowIndex: number, curVisibleColIndex: number, callback: (IgxColumnComponent) => boolean = null): ICellPosition { return super.getNextCell(currRowIndex, curVisibleColIndex, callback); } /** * @hidden @internal */ public override getPreviousCell(currRowIndex: number, curVisibleColIndex: number, callback: (IgxColumnComponent) => boolean = null): ICellPosition { return super.getPreviousCell(currRowIndex, curVisibleColIndex, callback); } /** * @hidden @internal */ public override getPinnedWidth(takeHidden = false) { return super.getPinnedWidth(takeHidden); } /** * @hidden @internal */ public override get totalHeight() { return this.calcHeight; } public getColumnGroupExpandState(col: IgxColumnComponent) { const state = this.columnGroupStates.get(col.field); // columns are expanded by default? return state !== undefined && state !== null ? state : false; } public toggleRowGroup(col: IgxColumnComponent, newState: boolean) { if (!col) return; if (this.hasMultipleValues) { const parentCols = col.parent ? col.parent.children.toArray() : this._autoGeneratedCols.filter(x => x.level === 0); const siblingCol = parentCols.filter(x => x.header === col.header && x !== col)[0]; const currIndex = parentCols.indexOf(col); const siblingIndex = parentCols.indexOf(siblingCol); if (currIndex < siblingIndex) { // clicked on the full hierarchy header this.resolveToggle(col, newState); siblingCol.headerTemplate = this.headerTemplate; } else { // clicked on summary parent column that contains just the measures col.headerTemplate = undefined; this.resolveToggle(siblingCol, newState); } } else { const parentCols = col.parent ? col.parent.children : this._autoGeneratedCols.filter(x => x.level === 0); const fieldColumn = parentCols.filter(x => x.header === col.header && !x.columnGroup)[0]; const groupColumn = parentCols.filter(x => x.header === col.header && x.columnGroup)[0]; this.resolveToggle(groupColumn, newState); if (newState) { fieldColumn.headerTemplate = this.headerTemplate; } else { fieldColumn.headerTemplate = undefined; } } } /** * @hidden @internal */ public override setupColumns() { super.setupColumns(); } /** * Auto-sizes row dimension cells. * * @remarks * Only sizes based on the dimension cells in view. * @example * ```typescript * this.grid.autoSizeRowDimension(dimension); * ``` * @param dimension The row dimension to size. */ public autoSizeRowDimension(dimension: IPivotDimension) { if (this.getDimensionType(dimension) === PivotDimensionType.Row) { const relatedDims = PivotUtil.flatten([dimension]).map(x => x.memberName); const content = this.rowDimensionContentCollection.filter(x => relatedDims.indexOf(x.dimension.memberName) !== -1); const headers = content.map(x => x.headerGroups.toArray()).flat().map(x => x.header && x.header.refInstance); const autoWidth = this.getLargesContentWidth(headers); dimension.width = autoWidth; this.pipeTrigger++; this.cdr.detectChanges(); } } /** * Inserts dimension in target collection by type at specified index or at the collection's end. * * @example * ```typescript * this.grid.insertDimensionAt(dimension, PivotDimensionType.Row, 1); * ``` * @param dimension The dimension that will be added. * @param targetCollectionType The target collection type to add to. Can be Row, Column or Filter. * @param index The index in the collection at which to add. * This parameter is optional. If not set it will add it to the end of the collection. */ public insertDimensionAt(dimension: IPivotDimension, targetCollectionType: PivotDimensionType, index?: number) { const targetCollection = this.getDimensionsByType(targetCollectionType); if (index !== undefined) { targetCollection.splice(index, 0, dimension); } else { targetCollection.push(dimension); } if (targetCollectionType === PivotDimensionType.Column) { this.setupColumns(); } this.pipeTrigger++; this.dimensionsChange.emit({ dimensions: targetCollection, dimensionCollectionType: targetCollectionType }); if (targetCollectionType === PivotDimensionType.Filter) { this.dimensionDataColumns = this.generateDimensionColumns(); this.reflow(); } this.pivotConfigurationChange.emit({ pivotConfiguration: this.pivotConfiguration }); } /** * Move dimension from its currently collection to the specified target collection by type at specified index or at the collection's end. * * @example * ```typescript * this.grid.moveDimension(dimension, PivotDimensionType.Row, 1); * ``` * @param dimension The dimension that will be moved. * @param targetCollectionType The target collection type to move it to. Can be Row, Column or Filter. * @param index The index in the collection at which to add. * This parameter is optional. If not set it will add it to the end of the collection. */ public moveDimension(dimension: IPivotDimension, targetCollectionType: PivotDimensionType, index?: number) { const prevCollectionType = this.getDimensionType(dimension); if (prevCollectionType === null) return; // remove from old collection this._removeDimensionInternal(dimension); // add to target this.insertDimensionAt(dimension, targetCollectionType, index); if (prevCollectionType === PivotDimensionType.Column) { this.setupColumns(); } } /** * Removes dimension from its currently collection. * @remarks * This is different than toggleDimension that enabled/disables the dimension. * This completely removes the specified dimension from the collection. * @example * ```typescript * this.grid.removeDimension(dimension); * ``` * @param dimension The dimension to be removed. */ public removeDimension(dimension: IPivotDimension) { const prevCollectionType = this.getDimensionType(dimension); this._removeDimensionInternal(dimension); if (prevCollectionType === PivotDimensionType.Column) { this.setupColumns(); } if (prevCollectionType === PivotDimensionType.Filter) { this.reflow(); } this.pipeTrigger++; this.cdr.detectChanges(); } /** * Toggles the dimension's enabled state on or off. * @remarks * The dimension remains in its current collection. This just changes its enabled state. * @example * ```typescript * this.grid.toggleDimension(dimension); * ``` * @param dimension The dimension to be toggled. */ public toggleDimension(dimension: IPivotDimension) { const dimType = this.getDimensionType(dimension); if (dimType === null) return; const collection = this.getDimensionsByType(dimType); dimension.enabled = !dimension.enabled; if (dimType === PivotDimensionType.Column) { this.setupColumns(); } if (!dimension.enabled && dimension.filter) { this.filteringService.clearFilter(dimension.memberName); } this.pipeTrigger++; this.dimensionsChange.emit({ dimensions: collection, dimensionCollectionType: dimType }); this.cdr.detectChanges(); if (dimType === PivotDimensionType.Filter) { this.reflow(); } this.pivotConfigurationChange.emit({ pivotConfiguration: this.pivotConfiguration }); } /** * Inserts value at specified index or at the end. * * @example * ```typescript * this.grid.insertValueAt(value, 1); * ``` * @param value The value definition that will be added. * @param index The index in the collection at which to add. * This parameter is optional. If not set it will add it to the end of the collection. */ public insertValueAt(value: IPivotValue, index?: number) { if (!this.pivotConfiguration.values) { this.pivotConfiguration.values = []; } const values = this.pivotConfiguration.values; if (index !== undefined) { values.splice(index, 0, value); } else { values.push(value); } this.setupColumns(); this.pipeTrigger++; this.cdr.detectChanges(); this.valuesChange.emit({ values }); this.pivotConfigurationChange.emit({ pivotConfiguration: this.pivotConfiguration }); } /** * Move value from its currently at specified index or at the end. * * @example * ```typescript * this.grid.moveValue(value, 1); * ``` * @param value The value that will be moved. * @param index The index in the collection at which to add. * This parameter is optional. If not set it will add it to the end of the collection. */ public moveValue(value: IPivotValue, index?: number) { if (this.pivotConfiguration.values.indexOf(value) === -1) return; // remove from old index this.removeValue(value); // add to new this.insertValueAt(value, index); } /** * Removes value from collection. * @remarks * This is different than toggleValue that enabled/disables the value. * This completely remove