UNPKG

igniteui-angular

Version:

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

1 lines • 434 kB
{"version":3,"file":"igniteui-angular-grids-pivot-grid.mjs","sources":["../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row-dimension-header.component.ts","../../../projects/igniteui-angular/grids/core/src/headers/grid-header.component.html","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row-header-group.component.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row-dimension-header-group.component.html","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-header-row.component.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-header-row.component.html","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-grid-navigation.service.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-filtering.service.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row-dimension-header-group.component.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row-dimension-content.component.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row-dimension-content.component.html","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-sort-strategy.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-sort-util.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-grid.directives.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-grid.pipes.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row.component.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row.component.html","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row-dimension-mrl-row.component.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-row-dimension-mrl-row.component.html","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-grid-row.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-grid.component.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-grid.component.html","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-data-selector.component.html","../../../projects/igniteui-angular/grids/pivot-grid/src/pivot-grid.module.ts","../../../projects/igniteui-angular/grids/pivot-grid/src/igniteui-angular-grids-pivot-grid.ts"],"sourcesContent":["import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, HostListener, inject } from '@angular/core';\n\nimport { PivotGridType, PivotRowLayoutType, PivotUtil } from 'igniteui-angular/grids/core';\n\nimport { IgxGridHeaderComponent } from 'igniteui-angular/grids/core';\nimport { IgxPivotColumnResizingService } from 'igniteui-angular/grids/core';\nimport { SortingIndexPipe } from 'igniteui-angular/grids/core';\nimport { NgTemplateOutlet, NgClass } from '@angular/common';\nimport { takeUntil } from 'rxjs/operators';\nimport { IgxIconComponent } from 'igniteui-angular/icon';\nimport { ISortingExpression, SortingDirection } from 'igniteui-angular/core';\n\n/**\n * @hidden\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'igx-pivot-row-dimension-header',\n templateUrl: '../../core/src/headers/grid-header.component.html',\n imports: [IgxIconComponent, NgTemplateOutlet, NgClass, SortingIndexPipe]\n})\nexport class IgxPivotRowDimensionHeaderComponent extends IgxGridHeaderComponent implements AfterViewInit {\n public override colResizingService = inject(IgxPivotColumnResizingService);\n public refInstance = inject(ElementRef<HTMLElement>);\n\n private pivotGrid: PivotGridType;\n\n constructor() {\n super();\n\n this.pivotGrid = this.grid as PivotGridType;\n this.pivotGrid.dimensionsSortingExpressionsChange\n .pipe(takeUntil(this._destroy$))\n .subscribe((_: ISortingExpression[]) => this.setSortIndex());\n }\n\n public ngAfterViewInit(): void {\n this.setSortIndex();\n }\n\n @HostListener('click', ['$event'])\n public override onClick(event: MouseEvent) {\n event.preventDefault();\n }\n\n /**\n * @hidden @internal\n */\n public override get selectable(): boolean {\n return false;\n }\n\n /**\n * @hidden @internal\n */\n public override onSortingIconClick(event) {\n event.stopPropagation();\n const dim = this.pivotGrid.getRowDimensionByName(this.column.field);\n const startDirection = dim.sortDirection || SortingDirection.None;\n const direction = startDirection + 1 > SortingDirection.Desc ?\n SortingDirection.None : startDirection + 1;\n this.pivotGrid.sortDimension(dim, direction);\n }\n\n protected override getSortDirection() {\n const dim = this.pivotGrid.getRowDimensionByName(this.column.field);\n this.sortDirection = dim?.sortDirection || SortingDirection.None;\n }\n\n protected setSortIndex() {\n if (this.column.sortable && this.sortIconContainer) {\n const visibleRows = this.pivotGrid.pivotUI.rowLayout === PivotRowLayoutType.Vertical ?\n this.pivotGrid.pivotConfiguration.rows :\n PivotUtil.flatten(this.pivotGrid.pivotConfiguration.rows);\n const dimIndex = visibleRows.findIndex((target) => target.memberName === this.column.field);\n const dim = visibleRows[dimIndex];\n let newSortIndex = -1;\n if (dim.sortDirection) {\n let priorSortedDims = 0;\n for (let i = 0; i < dimIndex; i++) {\n if (visibleRows[i].sortDirection) {\n priorSortedDims++;\n }\n }\n\n // Sort index starts from 1.\n newSortIndex = priorSortedDims + 1;\n }\n\n this.sortIconContainer.nativeElement.setAttribute(\"data-sortIndex\", newSortIndex >= 0 ? newSortIndex : \"\");\n }\n }\n}\n","<ng-template #defaultColumn>\n <span [title]=\"title\">{{ column.header || column.field }}</span>\n</ng-template>\n\n<ng-template #defaultESFHeaderIconTemplate>\n <igx-icon family=\"default\" name=\"more_vert\"></igx-icon>\n</ng-template>\n\n<ng-template #defaultSortHeaderIconTemplate>\n <igx-icon\n family=\"default\"\n [name]=\"sortDirection < 2 ? 'sort_asc' : 'sort_desc'\">\n </igx-icon>\n</ng-template>\n\n<span class=\"igx-grid-th__title\">\n <ng-container\n *ngTemplateOutlet=\"column.headerTemplate ? column.headerTemplate : defaultColumn; context: { $implicit: column, column: column}\">\n </ng-container>\n</span>\n@if (!column.columnGroup) {\n <div class=\"igx-grid-th__icons\">\n @if (column.sortable && !disabled) {\n <div #sortIconContainer class=\"sort-icon\"\n [attr.data-sortIndex]=\"(grid.sortingOptions.mode === 'single' && grid.sortingExpressions.length <=1) ? null : column.field | sortingIndex:grid.sortingExpressions\"\n (pointerdown)=\"onPointerDownIndicator($event)\" (click)=\"onSortingIconClick($event)\">\n <ng-container *ngTemplateOutlet=\"sortIconTemplate; context: { $implicit: this }\"></ng-container>\n </div>\n }\n @if (grid.allowFiltering && column.filterable && grid.filterMode === 'excelStyleFilter') {\n <div [ngClass]=\"filterIconClassName\" (pointerdown)=\"onPointerDownIndicator($event)\" (click)=\"onFilteringIconClick($event)\" >\n <ng-container *ngTemplateOutlet=\"esfIconTemplate; context: { $implicit: this }\"></ng-container>\n </div>\n }\n </div>\n}\n","import { ChangeDetectionStrategy, Component, HostBinding, inject, Input, ViewChild } from '@angular/core';\nimport { NgClass, NgStyle } from '@angular/common';\nimport {\n IGX_GRID_BASE,\n IgxColumnMovingDragDirective,\n IgxColumnMovingDropDirective,\n IgxGridHeaderGroupComponent,\n IgxHeaderGroupStylePipe,\n IgxPivotColumnResizingService,\n IgxPivotResizeHandleDirective,\n IPivotDimension,\n PivotGridType,\n PivotRowHeaderGroupType\n} from 'igniteui-angular/grids/core';\nimport { IgxPivotRowDimensionHeaderComponent } from './pivot-row-dimension-header.component';\nimport { IgxIconComponent } from 'igniteui-angular/icon';\nimport { SortingDirection } from 'igniteui-angular/core';\n\n/**\n * @hidden\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'igx-pivot-row-header-group',\n templateUrl: './pivot-row-dimension-header-group.component.html',\n imports: [IgxIconComponent, IgxPivotRowDimensionHeaderComponent, NgClass, NgStyle, IgxColumnMovingDragDirective, IgxColumnMovingDropDirective, IgxPivotResizeHandleDirective, IgxHeaderGroupStylePipe]\n})\nexport class IgxPivotRowHeaderGroupComponent extends IgxGridHeaderGroupComponent implements PivotRowHeaderGroupType {\n public override grid = inject<PivotGridType>(IGX_GRID_BASE);\n public override colResizingService = inject(IgxPivotColumnResizingService);\n\n /**\n * @hidden\n */\n @HostBinding('style.user-select')\n public userSelect = 'none';\n\n /**\n * @hidden\n */\n public get role(): string {\n return 'columnheader';\n }\n\n /**\n * @hidden\n * @internal\n */\n @Input()\n public rowIndex: number;\n\n @Input()\n public set dimWidth(value: number) {\n this.column.width = value + 'px';\n }\n public get dimWidth() {\n return parseFloat(this.column.width);\n }\n\n public get parent() {\n return this;\n };\n\n @Input()\n public rootDimension: IPivotDimension;\n\n @ViewChild(IgxPivotRowDimensionHeaderComponent)\n public override header: IgxPivotRowDimensionHeaderComponent;\n\n @HostBinding('attr.id')\n public override get headerID() {\n return `${this.grid.id}_-2_${this.rootDimension.memberName}_${this.visibleIndex}`;\n }\n\n @HostBinding('attr.title')\n public override get title() {\n return this.rootDimension.displayName;\n }\n\n /**\n * @hidden\n * @internal\n */\n public get visibleIndex(): number {\n const rows = this.grid.visibleRowDimensions;\n return rows.indexOf(this.rootDimension);\n }\n\n @HostBinding('class.igx-grid-th--active')\n public override get active() {\n const nav = this.grid.navigation;\n const node = nav.activeNode;\n return node && !this.column.columnGroup ?\n nav.isRowDimensionHeaderActive &&\n node.row === this.rowIndex &&\n node.column === this.visibleIndex :\n false;\n }\n\n @HostBinding('class.asc')\n public get sortAscendingStyle() {\n return this.rootDimension.sortDirection === SortingDirection.Asc;\n }\n\n @HostBinding('class.desc')\n public get sortDescendingStyle() {\n return this.rootDimension.sortDirection === SortingDirection.Desc;\n }\n\n @HostBinding('class.igx-grid-th--sortable')\n public get sortableStyle() {\n return true;\n }\n\n @HostBinding('class.igx-grid-th--sorted')\n public get sortedStyle() {\n return this.rootDimension.sortDirection !== undefined && this.rootDimension.sortDirection !== SortingDirection.None;\n }\n\n protected override get activeNode() {\n this.grid.navigation.isRowDimensionHeaderActive = true;\n this.grid.navigation.isRowHeaderActive = false;\n return {\n row: this.rowIndex, column: this.visibleIndex, level: null,\n mchCache: {\n level: 0,\n visibleIndex: this.visibleIndex\n },\n layout: null\n };\n }\n\n public override activate() {\n this.grid.navigation.setActiveNode(this.activeNode);\n }\n\n /**\n * @hidden @internal\n */\n public override pointerdown(_event: PointerEvent): void {\n this.activate();\n }\n\n /**\n * @hidden @internal\n */\n public override onMouseDown(_event: MouseEvent): void {\n this.activate();\n }\n\n public override get selectable(): boolean {\n return false;\n }\n\n protected getHeaderWidthFromDimension() {\n return this.grid.hasHorizontalLayout && this.dimWidth === -1 ? 'fit-content' : null;\n }\n}\n","<ng-template #defaultColumn>\n <span class=\"igx-grid-th__group-title\" [title]=\"title\">{{column.header}}</span>\n</ng-template>\n\n<ng-template #defaultCollapseIndicator>\n <igx-icon\n family=\"default\"\n [name]=\"column.expanded ? 'tree_collapse' : 'tree_expand'\">\n </igx-icon>\n</ng-template>\n\n@if (!column.columnGroup) {\n @if (grid.hasMovableColumns) {\n <span class=\"igx-grid-th__drop-indicator-left\"></span>\n }\n <igx-pivot-row-dimension-header\n [attr.role]=\"role\"\n class=\"igx-grid-th--fw\"\n [id]=\"header ? grid.id + '_' + header.title : grid.id + '_' + column.field\"\n [ngClass]=\"column.headerClasses\"\n [ngStyle]=\"column.headerStyles | igxHeaderGroupStyle:column:grid.pipeTrigger\"\n [igxColumnMovingDrag]=\"column\"\n [ghostHost]=\"grid.outlet.nativeElement\"\n [attr.droppable]=\"true\"\n (pointerdown)=\"pointerdown($event)\"\n [igxColumnMovingDrop]=\"column\"\n [column]=\"column\"\n (keydown)=\"grid.navigation.headerNavigation($event)\"\n [style.min-width]=\"getHeaderWidthFromDimension()\"\n [style.width]=\"getHeaderWidthFromDimension()\"\n >\n </igx-pivot-row-dimension-header>\n @if (!column.columnGroup && column.resizable) {\n <span class=\"igx-grid-th__resize-handle\"\n [igxPivotResizeHandle]=\"column\"\n [igxPivotResizeHandleHeader]=\"this\"\n [attr.draggable]=\"false\"\n [style.cursor]=\"colResizingService.resizeCursor\">\n </span>\n }\n @if (grid.hasMovableColumns) {\n <span class=\"igx-grid-th__drop-indicator-right\"></span>\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n OnChanges,\n QueryList,\n Renderer2,\n ViewChild,\n SimpleChanges,\n ViewChildren,\n HostBinding,\n inject\n} from '@angular/core';\nimport { NgTemplateOutlet, NgClass, NgStyle } from '@angular/common';\n\nimport { AbsoluteScrollStrategy, AutoPositionStrategy, ColumnType, OverlaySettings, PositionSettings, SortingDirection, VerticalAlignment } from 'igniteui-angular/core';\nimport {\n DropPosition,\n IGX_GRID_BASE,\n IgxExcelStyleColumnOperationsTemplateDirective,\n IgxExcelStyleFilterOperationsTemplateDirective,\n IgxExcelStyleSearchComponent,\n IgxGridExcelStyleFilteringComponent,\n IgxGridHeaderGroupComponent,\n IgxGridHeaderRowComponent,\n IgxGridTopLevelColumns,\n IgxHeaderGroupStylePipe,\n IPivotAggregator,\n IPivotDimension,\n IPivotValue,\n PivotDimensionType,\n PivotGridType,\n PivotUtil\n} from 'igniteui-angular/grids/core';\nimport { IgxPivotRowHeaderGroupComponent } from './pivot-row-header-group.component';\nimport { IgxDropDirective, IgxGridForOfDirective } from 'igniteui-angular/directives';\nimport { IBaseChipEventArgs, IgxChipComponent, IgxChipsAreaComponent } from 'igniteui-angular/chips';\nimport { IgxIconComponent } from 'igniteui-angular/icon';\nimport { IgxPrefixDirective, IgxSuffixDirective } from 'igniteui-angular/input-group';\nimport { IgxBadgeComponent } from 'igniteui-angular/badge';\nimport { IgxDropDownComponent, IgxDropDownItemComponent, IgxDropDownItemNavigationDirective, ISelectionEventArgs } from 'igniteui-angular/drop-down';\n\n/**\n *\n * For all intents & purposes treat this component as what a <thead> usually is in the default <table> element.\n *\n * This container holds the pivot grid header elements and their behavior/interactions.\n *\n * @hidden @internal\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'igx-pivot-header-row',\n templateUrl: './pivot-header-row.component.html',\n imports: [IgxDropDirective, IgxChipsAreaComponent, IgxChipComponent, IgxIconComponent,\n IgxPrefixDirective, IgxBadgeComponent, IgxSuffixDirective, IgxDropDownItemNavigationDirective,\n NgTemplateOutlet, IgxGridHeaderGroupComponent, NgClass, NgStyle, IgxGridForOfDirective,\n IgxDropDownComponent, IgxDropDownItemComponent, IgxGridExcelStyleFilteringComponent,\n IgxExcelStyleColumnOperationsTemplateDirective, IgxExcelStyleFilterOperationsTemplateDirective,\n IgxExcelStyleSearchComponent, IgxHeaderGroupStylePipe, IgxGridTopLevelColumns,\n IgxPivotRowHeaderGroupComponent]\n})\nexport class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent implements OnChanges {\n public override grid = inject<PivotGridType>(IGX_GRID_BASE);\n protected renderer = inject(Renderer2);\n\n public aggregateList: IPivotAggregator[] = [];\n\n public value: IPivotValue;\n public filterDropdownDimensions: Set<any> = new Set<any>();\n public filterAreaDimensions: Set<any> = new Set<any>();\n private _dropPos = DropPosition.AfterDropTarget;\n private _subMenuPositionSettings: PositionSettings = {\n verticalStartPoint: VerticalAlignment.Bottom,\n closeAnimation: undefined\n };\n private _subMenuOverlaySettings: OverlaySettings = {\n closeOnOutsideClick: true,\n modal: false,\n positionStrategy: new AutoPositionStrategy(this._subMenuPositionSettings),\n scrollStrategy: new AbsoluteScrollStrategy()\n };\n\n /**\n * @hidden @internal\n */\n @ViewChild('esf') public esf: any;\n\n /**\n * @hidden @internal\n */\n @ViewChild('filterAreaHidden', { static: false }) public filterArea;\n\n /**\n * @hidden @internal\n */\n @ViewChild('filterIcon') public filtersButton;\n\n /**\n * @hidden @internal\n */\n @ViewChild('dropdownChips') public dropdownChips;\n\n /**\n * @hidden @internal\n */\n @ViewChild('pivotFilterContainer') public pivotFilterContainer;\n\n /**\n * @hidden @internal\n */\n @ViewChild('pivotRowContainer') public pivotRowContainer;\n\n /**\n * @hidden\n * @internal\n */\n @ViewChildren('notifyChip')\n public notificationChips: QueryList<IgxChipComponent>;\n\n /**\n * @hidden\n * @internal\n * The virtualized part of the header row containing the unpinned header groups.\n */\n @ViewChildren('headerVirtualContainer', { read: IgxGridForOfDirective })\n public headerContainers: QueryList<IgxGridForOfDirective<ColumnType, ColumnType[]>>;\n\n /**\n * @hidden\n * @internal\n */\n @ViewChildren('rowDimensionHeaders')\n public rowDimensionHeaders: QueryList<IgxPivotRowHeaderGroupComponent>;\n\n public override get headerForOf() {\n return this.headerContainers?.last;\n }\n\n @HostBinding('attr.aria-activedescendant')\n public override get activeDescendant(): string {\n const activeElem = this.navigation.activeNode;\n if (!activeElem || !Object.keys(activeElem).length || this.grid.navigation.headerRowActiveDescendant) {\n return null;\n }\n\n if (this.navigation.isRowDimensionHeaderActive) {\n const activeHeader = this.grid.theadRow.rowDimensionHeaders.find(h => h.active);\n if (activeHeader) {\n const key = activeHeader.title ?? activeHeader.rootDimension?.memberName;\n return key ? `${this.grid.id}_${key}` : null;\n }\n return null;\n }\n\n return super.activeDescendant;\n }\n\n /**\n * @hidden\n * @internal\n * Default is a single empty level since default depth is 1\n */\n public columnDimensionsByLevel: any[] = [[]];\n\n /**\n * @hidden @internal\n */\n public get isFiltersButton(): boolean {\n let chipsWidth = 0;\n this.filterDropdownDimensions.clear();\n this.filterAreaDimensions.clear();\n if (this.filterArea?.chipsList && this.filterArea.chipsList.length !== 0) {\n const styles = getComputedStyle(this.pivotFilterContainer.nativeElement);\n const containerPaddings = parseFloat(styles.paddingLeft) + parseFloat(styles.paddingRight);\n chipsWidth += containerPaddings + (this.filtersButton && this.filterArea?.chipsList.length > 1 ? this.filtersButton.el.nativeElement.getBoundingClientRect().width : 0);\n this.filterArea.chipsList.forEach(chip => {\n const dim = this.grid.filterDimensions.find(x => x.memberName === chip.id);\n if (dim) {\n // 8 px margin between chips\n const currentChipWidth = chip.nativeElement.getBoundingClientRect().width + 8;\n if (chipsWidth + currentChipWidth < this.grid.pivotRowWidths) {\n this.filterAreaDimensions.add(dim);\n } else {\n this.filterDropdownDimensions.add(dim);\n }\n chipsWidth += currentChipWidth;\n }\n });\n return this.filterDropdownDimensions.size > 0;\n }\n return false;\n }\n\n /**\n * @hidden\n * @internal\n */\n public get totalDepth() {\n const columnDimensions = this.grid.columnDimensions;\n if (columnDimensions.length === 0) {\n return 1;\n }\n let totalDepth = columnDimensions.map(x => this.grid.data?.length > 0 ? PivotUtil.getDimensionDepth(x) + 1 : 0).reduce((acc, val) => acc + val);\n if (this.grid.hasMultipleValues) {\n totalDepth += 1;\n }\n return totalDepth;\n }\n\n /**\n * @hidden\n * @internal\n */\n public get maxContainerHeight() {\n return this.totalDepth * this.grid.renderedRowHeight;\n }\n\n /**\n * @hidden\n * @internal\n */\n public override get isLeafHeaderAriaHidden(): boolean {\n return super.isLeafHeaderAriaHidden || this.grid.navigation.isRowHeaderActive || this.grid.navigation.isRowDimensionHeaderActive;\n }\n\n /**\n * @hidden\n * @internal\n */\n public calcHeight(col: ColumnType, index: number) {\n return !col.columnGroup && col.level < this.totalDepth && col.level === index ? (this.totalDepth - col.level) * this.grid.rowHeight : this.grid.rowHeight;\n }\n\n /**\n * @hidden\n * @internal\n */\n public isDuplicateOfExistingParent(col: ColumnType, lvl: number) {\n const parentCollection = lvl > 0 ? this.columnDimensionsByLevel[lvl - 1] : [];\n const duplicate = parentCollection.indexOf(col) !== -1;\n\n return duplicate;\n }\n\n /**\n * @hidden\n * @internal\n */\n public isMultiRow(col: ColumnType, lvl: number) {\n const isLeaf = !col.columnGroup;\n return isLeaf && lvl !== this.totalDepth - 1;\n }\n\n /**\n * @hidden\n * @internal\n */\n public populateColumnDimensionsByLevel() {\n const res = [];\n for (let i = 0; i < this.totalDepth; i++) {\n res[i] = [];\n }\n const cols = this.unpinnedColumnCollection;\n // populate column dimension matrix recursively\n this.populateDimensionRecursively(cols.filter(x => x.level === 0), 0, res);\n this.columnDimensionsByLevel = res;\n }\n\n protected populateDimensionRecursively(currentLevelColumns: ColumnType[], level = 0, res: any[]) {\n currentLevelColumns.forEach(col => {\n if (res[level]) {\n res[level].push(col);\n if (col.columnGroup && col.children.length > 0) {\n const visibleColumns = col.children.toArray().filter(x => !x.hidden);\n this.populateDimensionRecursively(visibleColumns, level + 1, res);\n } else if (level < this.totalDepth - 1) {\n for (let i = level + 1; i <= this.totalDepth - 1; i++) {\n res[i].push(col);\n }\n }\n }\n });\n }\n\n /**\n * @hidden\n * @internal\n */\n public ngOnChanges(changes: SimpleChanges) {\n if (changes.unpinnedColumnCollection) {\n this.populateColumnDimensionsByLevel();\n }\n }\n\n /**\n * @hidden\n * @internal\n */\n public onDimDragStart(event, area) {\n this.cdr.detectChanges();\n for (const chip of this.notificationChips) {\n const parent = chip.nativeElement.parentElement;\n if (area.chipsList.toArray().indexOf(chip) === -1 &&\n parent.children.length > 0 &&\n parent.children.item(0).id !== 'empty') {\n chip.nativeElement.hidden = false;\n parent.parentElement.scrollTo({ left: chip.nativeElement.offsetLeft });\n }\n }\n }\n\n /**\n * @hidden\n * @internal\n */\n public onDimDragEnd() {\n for (const chip of this.notificationChips) {\n chip.nativeElement.hidden = true;\n }\n }\n\n /**\n * @hidden\n * @internal\n */\n public getAreaHeight(area: IgxChipsAreaComponent) {\n const chips = area.chipsList;\n return chips && chips.length > 0 ? chips.first.nativeElement.offsetHeight : 0;\n }\n\n /**\n * @hidden\n * @internal\n */\n public rowRemoved(event: IBaseChipEventArgs) {\n const row = this.grid.pivotConfiguration.rows.find(x => x.memberName === event.owner.id);\n this.grid.toggleDimension(row);\n }\n\n /**\n * @hidden\n * @internal\n */\n public columnRemoved(event: IBaseChipEventArgs) {\n const col = this.grid.pivotConfiguration.columns.find(x => x.memberName === event.owner.id);\n this.grid.toggleDimension(col);\n }\n\n /**\n * @hidden\n * @internal\n */\n public valueRemoved(event: IBaseChipEventArgs) {\n const value = this.grid.pivotConfiguration.values.find(x => x.member === event.owner.id || x.displayName === event.owner.id);\n this.grid.toggleValue(value);\n }\n\n /**\n * @hidden\n * @internal\n */\n public filterRemoved(event: IBaseChipEventArgs) {\n const filter = this.grid.pivotConfiguration.filters.find(x => x.memberName === event.owner.id);\n this.grid.toggleDimension(filter);\n if (this.filterDropdownDimensions.size > 0) {\n this.onFiltersAreaDropdownClick({ target: this.filtersButton.el.nativeElement }, undefined, false);\n } else {\n this.grid.filteringService.hideESF();\n }\n }\n\n public onFiltersSelectionChanged(event?: IBaseChipEventArgs) {\n this.dropdownChips.chipsList.forEach(chip => {\n if (chip.id !== event.owner.id) {\n chip.selected = false\n }\n });\n this.onFiltersAreaDropdownClick({ target: this.filtersButton.el.nativeElement }, this.grid.filterDimensions.find(dim => dim.memberName === event.owner.id), false);\n }\n\n /**\n * @hidden\n * @internal\n */\n public onFilteringIconPointerDown(event) {\n event.stopPropagation();\n event.preventDefault();\n }\n\n /**\n * @hidden\n * @internal\n */\n public onFilteringIconClick(event, dimension) {\n event.stopPropagation();\n event.preventDefault();\n const dim = dimension;\n const col = this.grid.dimensionDataColumns.find(x => x.field === dim.memberName || x.field === dim.member);\n this.grid.filteringService.toggleFilterDropdown(event.target, col);\n }\n\n /**\n * @hidden\n * @internal\n */\n public onSummaryClick(eventArgs, value: IPivotValue, dropdown: IgxDropDownComponent, chip: IgxChipComponent) {\n this._subMenuOverlaySettings.target = eventArgs.currentTarget;\n this.updateDropDown(value, dropdown, chip);\n }\n\n /**\n * @hidden @internal\n */\n public onFiltersAreaDropdownClick(event, dimension?, shouldReattach = true) {\n const dim = dimension || this.filterDropdownDimensions.values().next().value;\n const col = this.grid.dimensionDataColumns.find(x => x.field === dim.memberName || x.field === dim.member);\n if (shouldReattach) {\n this.dropdownChips.chipsList.forEach(chip => {\n chip.selected = false\n });\n this.dropdownChips.chipsList.first.selected = true;\n }\n this.grid.filteringService.toggleFiltersESF(this.esf, event.target, col, shouldReattach);\n }\n\n /**\n * @hidden\n * @internal\n */\n public onAggregationChange(event: ISelectionEventArgs) {\n\n if (!this.isSelected(event.newSelection.value)) {\n this.value.aggregate = event.newSelection.value;\n const isSingleValue = this.grid.values.length === 1;\n\n PivotUtil.updateColumnTypeByAggregator(this.grid.columns, this.value, isSingleValue);\n\n this.grid.pipeTrigger++;\n }\n }\n\n /**\n * @hidden\n * @internal\n */\n public isSelected(val: IPivotAggregator) {\n return this.value.aggregate.key === val.key;\n }\n\n /**\n * @hidden\n * @internal\n */\n public onChipSort(_event, dimension: IPivotDimension) {\n if (dimension.sortable === undefined || dimension.sortable) {\n const startDirection = dimension.sortDirection || SortingDirection.None;\n const direction = startDirection + 1 > SortingDirection.Desc ?\n SortingDirection.None : startDirection + 1;\n this.grid.sortDimension(dimension, direction);\n }\n }\n\n /**\n * @hidden\n * @internal\n */\n public onDimDragOver(event, dimension?: PivotDimensionType) {\n if (!event.dragChip || !event.dragChip.data?.pivotArea) return;\n const typeMismatch = dimension !== undefined ? this.grid.pivotConfiguration.values.find(x => x.member === event.dragChip.id\n || x.displayName === event.dragChip.id) :\n !this.grid.pivotConfiguration.values.find(x => x.member === event.dragChip.id || x.displayName === event.dragChip.id);\n if (typeMismatch) {\n // cannot drag between dimensions and value\n return;\n }\n // if we are in the left half of the chip, drop on the left\n // else drop on the right of the chip\n const clientRect = event.owner.nativeElement.getBoundingClientRect();\n const pos = clientRect.width / 2;\n\n this._dropPos = event.originalEvent.offsetX > pos ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget;\n if (this._dropPos === DropPosition.AfterDropTarget) {\n event.owner.nativeElement.previousElementSibling.style.visibility = 'hidden';\n event.owner.nativeElement.nextElementSibling.style.visibility = '';\n } else {\n event.owner.nativeElement.nextElementSibling.style.visibility = 'hidden';\n event.owner.nativeElement.previousElementSibling.style.visibility = '';\n }\n }\n\n /**\n * @hidden\n * @internal\n */\n public onDimDragLeave(event) {\n event.owner.nativeElement.previousElementSibling.style.visibility = 'hidden';\n event.owner.nativeElement.nextElementSibling.style.visibility = 'hidden';\n this._dropPos = DropPosition.AfterDropTarget;\n }\n\n /**\n * @hidden\n * @internal\n */\n public onAreaDragLeave(event, area) {\n const dataChips = area.chipsList.toArray().filter(x => this.notificationChips.toArray().indexOf(x) === -1);\n dataChips.forEach(element => {\n if (element.nativeElement.previousElementSibling) {\n element.nativeElement.previousElementSibling.style.visibility = 'hidden';\n }\n if (element.nativeElement.nextElementSibling) {\n element.nativeElement.nextElementSibling.style.visibility = 'hidden';\n }\n });\n }\n\n /**\n * @hidden\n * @internal\n */\n public onValueDrop(event, area) {\n if (!(event.dragChip && event.dragChip.data?.pivotArea) && !(event.dragData?.chip && !!event.dragData.chip.data.pivotArea)) return;\n //values can only be reordered\n const values = this.grid.pivotConfiguration.values;\n const dragId = event.dragChip?.id || event.dragData?.chip.id;\n const chipsArray = area.chipsList.toArray();\n let chipIndex = chipsArray.indexOf(event.owner) !== -1 ? chipsArray.indexOf(event.owner) : chipsArray.length;\n chipIndex = this._dropPos === DropPosition.AfterDropTarget ? chipIndex + 1 : chipIndex;\n const value = values.find(x => x.member === dragId || x.displayName === dragId);\n if (value) {\n const dragChipIndex = chipsArray.indexOf(event.dragChip || event.dragData.chip);\n this.grid.moveValue(value, dragChipIndex >= chipIndex ? chipIndex : chipIndex - 1);\n }\n }\n\n /**\n * @hidden\n * @internal\n */\n public onDimDrop(event, area, dimensionType: PivotDimensionType) {\n if (!(event.dragChip && event.dragChip.data?.pivotArea) && !(event.dragData?.chip && !!event.dragData.chip.data.pivotArea)) return;\n const dragId = event.dragChip?.id || event.dragData?.chip.id;\n const currentDim = this.grid.getDimensionsByType(dimensionType);\n const chipsArray = area.chipsList.toArray();\n const chip = chipsArray.find(x => x.id === dragId);\n const isNewChip = chip === undefined;\n const isReorder = event.owner.id !== undefined;\n //const chipIndex = chipsArray.indexOf(event.owner) !== -1 ? chipsArray.indexOf(event.owner) : chipsArray.length;\n const chipIndex = currentDim.findIndex(x => x.memberName === event.owner.id) !== -1 ?\n currentDim.findIndex(x => x.memberName === event.owner.id) : currentDim.length;\n const targetIndex = this._dropPos === DropPosition.AfterDropTarget ? chipIndex + 1 : chipIndex;\n if (isNewChip) {\n // chip moved from an external collection\n const dim = this.grid.allDimensions.find(x => x && x.memberName === dragId);\n if (!dim) {\n // you have dragged something that is not a dimension\n return;\n }\n this.grid.moveDimension(dim, dimensionType, targetIndex);\n } else if (isReorder) {\n // chip from same collection, reordered.\n const newDim = currentDim.find(x => x.memberName === dragId);\n const dragChipIndex = currentDim.findIndex(x => x.memberName === dragId);\n this.grid.moveDimension(newDim, dimensionType, dragChipIndex > chipIndex ? targetIndex : targetIndex - 1);\n }\n this.grid.pipeTrigger++;\n this.grid.dimensionsChange.emit({ dimensions: currentDim, dimensionCollectionType: dimensionType });\n // clean states\n this.onDimDragEnd();\n this.onAreaDragLeave(event, area);\n }\n\n protected updateDropDown(value: IPivotValue, dropdown: IgxDropDownComponent, chip: IgxChipComponent) {\n this.value = value;\n dropdown.width = chip.nativeElement.clientWidth + 'px';\n this.aggregateList = PivotUtil.getAggregateList(value, this.grid);\n this.cdr.detectChanges();\n dropdown.open(this._subMenuOverlaySettings);\n }\n\n protected getRowDimensionColumn(dim: IPivotDimension): ColumnType {\n return this.grid.dimensionDataColumns ? this.grid.dimensionDataColumns.find((col) => col.field === dim.memberName) : null;\n }\n}\n","<div>\n <div class=\"igx-grid-thead__wrapper igx-grid-thead__wrapper--pivot\" role=\"row\" [style.width.px]=\"width\">\n <div class=\"igx-grid__tr\" role=\"row\" [style.width.px]=\"width\">\n <div class='igx-grid__tr-pivot--filter-container'>\n @if (grid.pivotUI.showConfiguration) {\n <div #pivotFilterContainer\n class=\"igx-grid__tr-pivot igx-grid__tr-pivot--filter\" [style.min-width.px]=\"grid.pivotRowWidths - 1\"\n [style.max-width.px]=\"grid.pivotRowWidths - 1\" (igxDragLeave)=\"onAreaDragLeave($event, filterArea)\"\n igxDrop (dropped)=\"onDimDrop($event, filterArea, 2)\" (pointerdown)=\"$event.preventDefault()\">\n <!-- Filter area -->\n <igx-chips-area #filterArea droppable='true'>\n @if (grid.filterDimensions.length === 0) {\n <span id='empty' igxDrop (dropped)=\"onDimDrop($event, filterArea, 2)\"\n class='igx-grid__pivot-empty-chip-area'>{{grid.resourceStrings.igx_grid_pivot_empty_filter_drop_area}}</span>\n }\n @for (filter of this.filterAreaDimensions; track filter; let last = $last) {\n <span class=\"igx-grid__tr-pivot--chip_drop_indicator\"\n [style.height.px]='getAreaHeight(filterArea)'></span>\n <igx-chip [id]=\"filter.memberName\" [draggable]=\"true\" [data]=\"{ pivotArea: 'filter' }\"\n [removable]=\"true\" (remove)=\"filterRemoved($event)\" (dragOver)=\"onDimDragOver($event, 2)\"\n (dragLeave)=\"onDimDragLeave($event)\" (dragDrop)=\"onDimDrop($event, filterArea, 2)\"\n (moveStart)='onDimDragStart($event, filterArea)' (moveEnd)='onDimDragEnd()'>\n <igx-icon\n family=\"default\"\n name=\"filter_list\"\n igxPrefix\n (pointerdown)='onFilteringIconPointerDown($event)'\n (click)='onFilteringIconClick($event, filter)'>\n </igx-icon>\n {{filter.displayName || filter.memberName}}\n </igx-chip>\n @if (last) {\n <span class=\"igx-grid__tr-pivot--chip_drop_indicator\"\n [style.height.px]='getAreaHeight(filterArea)'></span>\n }\n }\n <igx-chip igxDrop (dragDrop)=\"onDimDrop($event, filterArea, 2)\" #notifyChip [hidden]='true'>\n {{grid.resourceStrings.igx_grid_pivot_filter_drop_chip}}\n </igx-chip>\n </igx-chips-area>\n @if (isFiltersButton && grid.filterDimensions.length !== 0) {\n <div class=\"igx-grid__pivot-filter-toggle\">\n <igx-icon\n family=\"default\"\n name=\"filter_list\"\n #filterIcon\n (pointerdown)='onFilteringIconPointerDown($event)'\n (click)='onFiltersAreaDropdownClick($event)'>\n </igx-icon>\n <igx-badge value=\"{{this.filterDropdownDimensions.size}}\"></igx-badge>\n </div>\n }\n </div>\n }\n <div class='igx-grid__tr-pivot--drop-row-area'>\n @if (grid.pivotUI.showConfiguration && grid.pivotUI.showRowHeaders) {\n <div #pivotRowContainer [style.width.px]=\"grid.pivotRowWidths - 1\"\n class=\"igx-grid__tr-pivot igx-grid__tr-pivot--small-row-area\" igxDrop\n (igxDragLeave)=\"onAreaDragLeave($event, rowArea)\"\n (dropped)=\"onDimDrop($event, rowArea, 0)\">\n <igx-chips-area #rowArea droppable='true'>\n @if (grid.rowDimensions.length === 0) {\n <span id='empty' igxDrop (dropped)=\"onDimDrop($event, rowArea, 0)\"\n class='igx-grid__pivot-empty-chip-area'>{{grid.resourceStrings.igx_grid_pivot_empty_row_drop_area}}</span>\n }\n @for (row of grid.rowDimensions; track row.memberName; let last = $last) {\n <span class=\"igx-grid__tr-pivot--chip_drop_indicator\"\n [style.height.px]='getAreaHeight(rowArea)'></span>\n <igx-chip [draggable]=\"true\" [id]=\"row.memberName\" [data]=\"{ pivotArea: 'row' }\"\n [removable]=\"true\" (remove)=\"rowRemoved($event)\" (dragLeave)=\"onDimDragLeave($event)\"\n (dragDrop)=\"onDimDrop($event, rowArea, 0)\" (dragOver)=\"onDimDragOver($event, 0)\"\n (moveStart)='onDimDragStart($event, rowArea)' (moveEnd)='onDimDragEnd()'\n (click)=\"onChipSort($event, row)\">\n <igx-icon igxPrefix family=\"default\" name=\"table_rows\"></igx-icon>\n <igx-icon\n family=\"default\"\n name=\"filter_list\"\n igxPrefix\n (pointerdown)='onFilteringIconPointerDown($event)'\n (click)='onFilteringIconClick($event, row)'>\n </igx-icon>\n {{ row.displayName || row.memberName}}\n @if (row.sortDirection) {\n <igx-icon\n family=\"default\"\n [name]=\"row.sortDirection < 2 ? 'sort_asc' : 'sort_desc'\"\n igxSuffix>\n </igx-icon>\n }\n </igx-chip>\n @if (last) {\n <span class=\"igx-grid__tr-pivot--chip_drop_indicator\"\n [style.height.px]='getAreaHeight(rowArea)'></span>\n }\n }\n <igx-chip igxDrop (dragDrop)=\"onDimDrop($event, rowArea, 0)\" #notifyChip [hidden]='true'>\n {{grid.resourceStrings.igx_grid_pivot_row_drop_chip}}\n </igx-chip>\n </igx-chips-area>\n </div>\n }\n </div>\n </div>\n\n <div class=\"igx-grid__tr-pivot-group\">\n @if (grid.pivotUI.showConfiguration) {\n <div #pivotColumnContainer class=\"igx-grid__tr-pivot\"\n (dropped)=\"onDimDrop($event, colArea, 1)\" igxDrop (igxDragLeave)=\"onAreaDragLeave($event, colArea)\">\n <!-- Columns area -->\n <igx-chips-area #colArea droppable='true'>\n @if (grid.columnDimensions.length === 0) {\n <span id='empty' (dropped)=\"onDimDrop($event, colArea, 1)\" igxDrop\n class='igx-grid__pivot-empty-chip-area'>\n {{grid.resourceStrings.igx_grid_pivot_empty_column_drop_area}}</span>\n }\n @for (col of grid.columnDimensions; track col.memberName; let last = $last) {\n <span class=\"igx-grid__tr-pivot--chip_drop_indicator\"\n [style.height.px]='getAreaHeight(colArea)'></span>\n <igx-chip [draggable]=\"true\" [id]=\"col.memberName\" [data]=\"{ pivotArea: 'column' }\"\n [removable]=\"true\" (remove)=\"columnRemoved($event)\" (dragOver)=\"onDimDragOver($event, 1)\"\n (dragLeave)=\"onDimDragLeave($event)\" (dragDrop)=\"onDimDrop($event, colArea, 1)\"\n (moveStart)='onDimDragStart($event, colArea)' (moveEnd)='onDimDragEnd()'\n (click)=\"onChipSort($event, col)\">\n <igx-icon\n family=\"default\"\n name=\"view_column\"\n igxPrefix>\n </igx-icon>\n <igx-icon\n family=\"default\"\n name=\"filter_list\"\n igxPrefix\n (pointerdown)='onFilteringIconPointerDown($event)'\n (click)='onFilteringIconClick($event, col)'>\n </igx-icon>\n {{col.displayName || col.memberName}}\n @if (col.sortDirection) {\n <igx-icon\n family=\"default\"\n [name]=\"col.sortDirection < 2 ? 'sort_asc' : 'sort_desc'\"\n igxSuffix>\n </igx-icon>\n }\n </igx-chip>\n @if (last) {\n <span class=\"igx-grid__tr-pivot--chip_drop_indicator\"\n [style.height.px]='getAreaHeight(colArea)'></span>\n }\n }\n <igx-chip igxDrop (dragDrop)=\"onDimDrop($event, colArea, 1)\" #notifyChip [hidden]='true'>\n {{grid.resourceStrings.igx_grid_pivot_column_drop_chip}}\n </igx-chip>\n </igx-chips-area>\n </div>\n }\n\n @if (grid.pivotUI.showConfiguration) {\n <div #pivotValueContainer class=\"igx-grid__tr-pivot\"\n (pointerdown)=\"$event.preventDefault()\" (dropped)=\"onValueDrop($event, valueArea)\" igxDrop\n (igxDragLeave)=\"onAreaDragLeave($event, valueArea)\">\n <!-- Value area -->\n <igx-chips-area #valueArea droppable='true'>\n @if (grid.values.length === 0) {\n <span id='empty' (dropped)=\"onValueDrop($event, valueArea)\" igxDrop\n class='igx-grid__pivot-empty-chip-area'>{{grid.resourceStrings.igx_grid_pivot_empty_value_drop_area}}</span>\n }\n @for (value of grid.values; track value.member; let last = $last) {\n <span class=\"igx-grid__tr-pivot--chip_drop_indicator\"\n [style.height.px]='getAreaHeight(valueArea)'></span>\n <igx-chip #currChip [draggable]=\"true\" [id]=\"value.displayName || value.member\" [data]=\"{ pivotArea: 'value' }\"\n [removable]=\"true\" (remove)=\"valueRemoved($event)\"\n (dragLeave)=\"onDimDragLeave($event)\" (dragOver)=\"onDimDragOver($event)\"\n (dragDrop)=\"onValueDrop($event, valueArea)\">\n <div class=\"igx-grid__tr-pivot-toggle-icons\" igxPrefix\n (click)='onSummaryClick($event, value, dropdown, currChip)'\n (pointerdown)='$event.stopPropagation()' [igxDropDownItemNavigation]=\"dropdown\">\n <igx-icon family=\"default\" name=\"functions\"></igx-icon>\n <igx-icon family=\"default\" name=\"arrow_drop_down\"></igx-icon>\n </div>\n <ng-container *ngTemplateOutlet=\"grid.valueChipTemplate ? grid.valueChipTemplate : valueChipDefaultTemplate; context: { $implicit: value }\"></ng-container>\n </igx-chip>\n @if (last) {\n <span class=\"igx-grid__tr-pivot--chip_drop_indicator\"\n [style.height.px]='getAreaHeight(valueArea)'></span>\n }\n }\n <igx-chip igxDrop (dragDrop)=\"onValueDrop($event, valueArea)\" #notifyValueChip [hidden]='true'>\n {{grid.resourceStrings.igx_grid_p