UNPKG

igniteui-angular

Version:

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

678 lines (675 loc) 353 kB
import { __decorate } from 'tslib'; import * as i0 from '@angular/core'; import { inject, ElementRef, HostListener, ChangeDetectionStrategy, Component, HostBinding, ViewChild, Input, Renderer2, ViewChildren, Injectable, NgZone, Injector, EnvironmentInjector, ViewContainerRef, createComponent, TemplateRef, Directive, Pipe, forwardRef, EventEmitter, booleanAttribute, Output, ContentChild, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef, NgModule } from '@angular/core'; import { NgTemplateOutlet, NgClass, NgStyle } from '@angular/common'; import { takeUntil, take, timeout, first } from 'rxjs/operators'; import { IgxGridHeaderComponent, IgxPivotColumnResizingService, PivotRowLayoutType, PivotUtil, SortingIndexPipe, IgxGridHeaderGroupComponent, IGX_GRID_BASE, IgxColumnMovingDragDirective, IgxColumnMovingDropDirective, IgxPivotResizeHandleDirective, IgxHeaderGroupStylePipe, IgxGridHeaderRowComponent, DropPosition, IgxGridExcelStyleFilteringComponent, IgxExcelStyleColumnOperationsTemplateDirective, IgxExcelStyleFilterOperationsTemplateDirective, IgxExcelStyleSearchComponent, IgxGridTopLevelColumns, IgxGridNavigationService, PivotSummaryPosition, IgxFilteringService, DimensionValuesFilteringStrategy, IgxColumnComponent, DEFAULT_PIVOT_KEYS, PivotRowDimensionsStrategy, PivotColumnDimensionsStrategy, GridBaseAPIService, IgxRowDirective, IgxGridCellComponent, IgxGridNotGroupedPipe, IgxGridCellStylesPipe, IgxGridTransactionStatePipe, FilterMode, PivotDimensionType, NoopPivotDimensionsStrategy, IgxPivotDateDimension, IgxColumnGroupComponent, IgxGridBodyDirective, IgxGridDragSelectDirective, IgxPivotGridColumnResizerComponent, IgxGridRowClassesPipe, IgxGridRowStylesPipe, IgxGridCRUDService, IgxGridValidationService, IgxGridSummaryService, IgxGridSelectionService, IgxColumnResizingService, IGX_GRID_SERVICE_BASE, WatchChanges, IgxGridFooterComponent, IgxAdvancedFilteringDialogComponent, IgxRowExpandedIndicatorDirective, IgxRowCollapsedIndicatorDirective, IgxHeaderExpandedIndicatorDirective, IgxHeaderCollapsedIndicatorDirective, IgxExcelStyleHeaderIconDirective, IgxSortAscendingHeaderIconDirective, IgxSortDescendingHeaderIconDirective, IgxSortHeaderIconDirective, IgxDragIndicatorIconDirective, IgxRowDragGhostDirective, IgxGridStateDirective, IgxGridPinningActionsComponent, IgxGridEditingActionsComponent, IgxGridActionsBaseDirective, IgxGridActionButtonComponent, IgxFilterCellTemplateDirective, IgxSummaryTemplateDirective, IgxCellTemplateDirective, IgxCellValidationErrorDirective, IgxCellHeaderTemplateDirective, IgxCellFooterTemplateDirective, IgxCellEditorTemplateDirective, IgxCollapsibleIndicatorTemplateDirective, IgxColumnLayoutComponent, IgxColumnActionsComponent, IgxColumnHidingDirective, IgxColumnPinningDirective, IgxRowSelectorDirective, IgxGroupByRowSelectorDirective, IgxHeadSelectorDirective, IgxCSVTextDirective, IgxExcelTextDirective, IgxGridToolbarActionsComponent, IgxGridToolbarAdvancedFilteringComponent, IgxGridToolbarComponent, IgxGridToolbarExporterComponent, IgxGridToolbarHidingComponent, IgxGridToolbarPinningComponent, IgxGridToolbarTitleComponent, IgxGridToolbarDirective, IgxExcelStyleHeaderComponent, IgxExcelStyleSortingComponent, IgxExcelStylePinningComponent, IgxExcelStyleHidingComponent, IgxExcelStyleSelectingComponent, IgxExcelStyleClearFiltersComponent, IgxExcelStyleConditionalFilterComponent, IgxExcelStyleMovingComponent, IgxExcelStyleLoadingValuesTemplateDirective } from 'igniteui-angular/grids/core'; import { SortingDirection, VerticalAlignment, AbsoluteScrollStrategy, AutoPositionStrategy, HEADER_KEYS, ROW_EXPAND_KEYS, ROW_COLLAPSE_KEYS, FilteringExpressionsTree, FilteringLogic, DefaultSortingStrategy, GridColumnDataType, parseDate, cloneArray, FilterUtil, DataUtil, columnFieldPath, resolveNestedPath, DefaultDataCloneStrategy, ɵSize as _Size, resizeObservable, IgxOverlayOutletDirective } from 'igniteui-angular/core'; import { IgxIconComponent } from 'igniteui-angular/icon'; import { IgxDropDirective, IgxGridForOfDirective, IgxTemplateOutletDirective, IgxToggleDirective, IgxForOfSyncService, IgxForOfScrollSyncService, IgxDragDirective, IgxDragHandleDirective } from 'igniteui-angular/directives'; import { IgxChipsAreaComponent, IgxChipComponent } from 'igniteui-angular/chips'; import { IgxPrefixDirective, IgxSuffixDirective, IgxInputGroupComponent, IgxInputDirective } from 'igniteui-angular/input-group'; import { IgxBadgeComponent } from 'igniteui-angular/badge'; import { IgxDropDownItemNavigationDirective, IgxDropDownComponent, IgxDropDownItemComponent } from 'igniteui-angular/drop-down'; import { IgxCheckboxComponent } from 'igniteui-angular/checkbox'; import { IgxCircularProgressBarComponent } from 'igniteui-angular/progressbar'; import { IgxSnackbarComponent } from 'igniteui-angular/snackbar'; import { IgxGridBaseDirective } from 'igniteui-angular/grids/grid'; import { useAnimation } from '@angular/animations'; import { fadeIn, fadeOut } from 'igniteui-angular/animations'; import { IgxListComponent, IgxListItemComponent } from 'igniteui-angular/list'; import { IgxAccordionComponent } from 'igniteui-angular/accordion'; import { IgxExpansionPanelComponent, IgxExpansionPanelHeaderComponent, IgxExpansionPanelTitleDirective, IgxExpansionPanelBodyComponent } from 'igniteui-angular/expansion-panel'; /** * @hidden */ class IgxPivotRowDimensionHeaderComponent extends IgxGridHeaderComponent { constructor() { super(); this.colResizingService = inject(IgxPivotColumnResizingService); this.refInstance = inject((ElementRef)); this.pivotGrid = this.grid; this.pivotGrid.dimensionsSortingExpressionsChange .pipe(takeUntil(this._destroy$)) .subscribe((_) => this.setSortIndex()); } ngAfterViewInit() { this.setSortIndex(); } onClick(event) { event.preventDefault(); } /** * @hidden @internal */ get selectable() { return false; } /** * @hidden @internal */ onSortingIconClick(event) { event.stopPropagation(); const dim = this.pivotGrid.getRowDimensionByName(this.column.field); const startDirection = dim.sortDirection || SortingDirection.None; const direction = startDirection + 1 > SortingDirection.Desc ? SortingDirection.None : startDirection + 1; this.pivotGrid.sortDimension(dim, direction); } getSortDirection() { const dim = this.pivotGrid.getRowDimensionByName(this.column.field); this.sortDirection = dim?.sortDirection || SortingDirection.None; } setSortIndex() { if (this.column.sortable && this.sortIconContainer) { const visibleRows = this.pivotGrid.pivotUI.rowLayout === PivotRowLayoutType.Vertical ? this.pivotGrid.pivotConfiguration.rows : PivotUtil.flatten(this.pivotGrid.pivotConfiguration.rows); const dimIndex = visibleRows.findIndex((target) => target.memberName === this.column.field); const dim = visibleRows[dimIndex]; let newSortIndex = -1; if (dim.sortDirection) { let priorSortedDims = 0; for (let i = 0; i < dimIndex; i++) { if (visibleRows[i].sortDirection) { priorSortedDims++; } } // Sort index starts from 1. newSortIndex = priorSortedDims + 1; } this.sortIconContainer.nativeElement.setAttribute("data-sortIndex", newSortIndex >= 0 ? newSortIndex : ""); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxPivotRowDimensionHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: IgxPivotRowDimensionHeaderComponent, isStandalone: true, selector: "igx-pivot-row-dimension-header", host: { listeners: { "click": "onClick($event)" } }, usesInheritance: true, ngImport: i0, template: "<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", dependencies: [{ kind: "component", type: IgxIconComponent, selector: "igx-icon", inputs: ["ariaHidden", "family", "name", "active"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: SortingIndexPipe, name: "sortingIndex" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxPivotRowDimensionHeaderComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'igx-pivot-row-dimension-header', imports: [IgxIconComponent, NgTemplateOutlet, NgClass, SortingIndexPipe], template: "<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" }] }], ctorParameters: () => [], propDecorators: { onClick: [{ type: HostListener, args: ['click', ['$event']] }] } }); /** * @hidden */ class IgxPivotRowHeaderGroupComponent extends IgxGridHeaderGroupComponent { constructor() { super(...arguments); this.grid = inject(IGX_GRID_BASE); this.colResizingService = inject(IgxPivotColumnResizingService); /** * @hidden */ this.userSelect = 'none'; } /** * @hidden */ get role() { return 'columnheader'; } set dimWidth(value) { this.column.width = value + 'px'; } get dimWidth() { return parseFloat(this.column.width); } get parent() { return this; } ; get headerID() { return `${this.grid.id}_-2_${this.rootDimension.memberName}_${this.visibleIndex}`; } get title() { return this.rootDimension.displayName; } /** * @hidden * @internal */ get visibleIndex() { const rows = this.grid.visibleRowDimensions; return rows.indexOf(this.rootDimension); } get active() { const nav = this.grid.navigation; const node = nav.activeNode; return node && !this.column.columnGroup ? nav.isRowDimensionHeaderActive && node.row === this.rowIndex && node.column === this.visibleIndex : false; } get sortAscendingStyle() { return this.rootDimension.sortDirection === SortingDirection.Asc; } get sortDescendingStyle() { return this.rootDimension.sortDirection === SortingDirection.Desc; } get sortableStyle() { return true; } get sortedStyle() { return this.rootDimension.sortDirection !== undefined && this.rootDimension.sortDirection !== SortingDirection.None; } get activeNode() { this.grid.navigation.isRowDimensionHeaderActive = true; this.grid.navigation.isRowHeaderActive = false; return { row: this.rowIndex, column: this.visibleIndex, level: null, mchCache: { level: 0, visibleIndex: this.visibleIndex }, layout: null }; } activate() { this.grid.navigation.setActiveNode(this.activeNode); } /** * @hidden @internal */ pointerdown(_event) { this.activate(); } /** * @hidden @internal */ onMouseDown(_event) { this.activate(); } get selectable() { return false; } getHeaderWidthFromDimension() { return this.grid.hasHorizontalLayout && this.dimWidth === -1 ? 'fit-content' : null; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxPivotRowHeaderGroupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: IgxPivotRowHeaderGroupComponent, isStandalone: true, selector: "igx-pivot-row-header-group", inputs: { rowIndex: "rowIndex", dimWidth: "dimWidth", rootDimension: "rootDimension" }, host: { properties: { "style.user-select": "this.userSelect", "attr.id": "this.headerID", "attr.title": "this.title", "class.igx-grid-th--active": "this.active", "class.asc": "this.sortAscendingStyle", "class.desc": "this.sortDescendingStyle", "class.igx-grid-th--sortable": "this.sortableStyle", "class.igx-grid-th--sorted": "this.sortedStyle" } }, viewQueries: [{ propertyName: "header", first: true, predicate: IgxPivotRowDimensionHeaderComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<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", dependencies: [{ kind: "component", type: IgxIconComponent, selector: "igx-icon", inputs: ["ariaHidden", "family", "name", "active"] }, { kind: "component", type: IgxPivotRowDimensionHeaderComponent, selector: "igx-pivot-row-dimension-header" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: IgxColumnMovingDragDirective, selector: "[igxColumnMovingDrag]", inputs: ["igxColumnMovingDrag"] }, { kind: "directive", type: IgxColumnMovingDropDirective, selector: "[igxColumnMovingDrop]", inputs: ["igxColumnMovingDrop"] }, { kind: "directive", type: IgxPivotResizeHandleDirective, selector: "[igxPivotResizeHandle]", inputs: ["igxPivotResizeHandle", "igxPivotResizeHandleHeader"] }, { kind: "pipe", type: IgxHeaderGroupStylePipe, name: "igxHeaderGroupStyle" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxPivotRowHeaderGroupComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'igx-pivot-row-header-group', imports: [IgxIconComponent, IgxPivotRowDimensionHeaderComponent, NgClass, NgStyle, IgxColumnMovingDragDirective, IgxColumnMovingDropDirective, IgxPivotResizeHandleDirective, IgxHeaderGroupStylePipe], template: "<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" }] }], propDecorators: { userSelect: [{ type: HostBinding, args: ['style.user-select'] }], rowIndex: [{ type: Input }], dimWidth: [{ type: Input }], rootDimension: [{ type: Input }], header: [{ type: ViewChild, args: [IgxPivotRowDimensionHeaderComponent] }], headerID: [{ type: HostBinding, args: ['attr.id'] }], title: [{ type: HostBinding, args: ['attr.title'] }], active: [{ type: HostBinding, args: ['class.igx-grid-th--active'] }], sortAscendingStyle: [{ type: HostBinding, args: ['class.asc'] }], sortDescendingStyle: [{ type: HostBinding, args: ['class.desc'] }], sortableStyle: [{ type: HostBinding, args: ['class.igx-grid-th--sortable'] }], sortedStyle: [{ type: HostBinding, args: ['class.igx-grid-th--sorted'] }] } }); /** * * For all intents & purposes treat this component as what a <thead> usually is in the default <table> element. * * This container holds the pivot grid header elements and their behavior/interactions. * * @hidden @internal */ class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent { constructor() { super(...arguments); this.grid = inject(IGX_GRID_BASE); this.renderer = inject(Renderer2); this.aggregateList = []; this.filterDropdownDimensions = new Set(); this.filterAreaDimensions = new Set(); this._dropPos = DropPosition.AfterDropTarget; this._subMenuPositionSettings = { verticalStartPoint: VerticalAlignment.Bottom, closeAnimation: undefined }; this._subMenuOverlaySettings = { closeOnOutsideClick: true, modal: false, positionStrategy: new AutoPositionStrategy(this._subMenuPositionSettings), scrollStrategy: new AbsoluteScrollStrategy() }; /** * @hidden * @internal * Default is a single empty level since default depth is 1 */ this.columnDimensionsByLevel = [[]]; } get headerForOf() { return this.headerContainers?.last; } get activeDescendant() { const activeElem = this.navigation.activeNode; if (!activeElem || !Object.keys(activeElem).length || this.grid.navigation.headerRowActiveDescendant) { return null; } if (this.navigation.isRowDimensionHeaderActive) { const activeHeader = this.grid.theadRow.rowDimensionHeaders.find(h => h.active); if (activeHeader) { const key = activeHeader.title ?? activeHeader.rootDimension?.memberName; return key ? `${this.grid.id}_${key}` : null; } return null; } return super.activeDescendant; } /** * @hidden @internal */ get isFiltersButton() { let chipsWidth = 0; this.filterDropdownDimensions.clear(); this.filterAreaDimensions.clear(); if (this.filterArea?.chipsList && this.filterArea.chipsList.length !== 0) { const styles = getComputedStyle(this.pivotFilterContainer.nativeElement); const containerPaddings = parseFloat(styles.paddingLeft) + parseFloat(styles.paddingRight); chipsWidth += containerPaddings + (this.filtersButton && this.filterArea?.chipsList.length > 1 ? this.filtersButton.el.nativeElement.getBoundingClientRect().width : 0); this.filterArea.chipsList.forEach(chip => { const dim = this.grid.filterDimensions.find(x => x.memberName === chip.id); if (dim) { // 8 px margin between chips const currentChipWidth = chip.nativeElement.getBoundingClientRect().width + 8; if (chipsWidth + currentChipWidth < this.grid.pivotRowWidths) { this.filterAreaDimensions.add(dim); } else { this.filterDropdownDimensions.add(dim); } chipsWidth += currentChipWidth; } }); return this.filterDropdownDimensions.size > 0; } return false; } /** * @hidden * @internal */ get totalDepth() { const columnDimensions = this.grid.columnDimensions; if (columnDimensions.length === 0) { return 1; } let totalDepth = columnDimensions.map(x => this.grid.data?.length > 0 ? PivotUtil.getDimensionDepth(x) + 1 : 0).reduce((acc, val) => acc + val); if (this.grid.hasMultipleValues) { totalDepth += 1; } return totalDepth; } /** * @hidden * @internal */ get maxContainerHeight() { return this.totalDepth * this.grid.renderedRowHeight; } /** * @hidden * @internal */ get isLeafHeaderAriaHidden() { return super.isLeafHeaderAriaHidden || this.grid.navigation.isRowHeaderActive || this.grid.navigation.isRowDimensionHeaderActive; } /** * @hidden * @internal */ calcHeight(col, index) { return !col.columnGroup && col.level < this.totalDepth && col.level === index ? (this.totalDepth - col.level) * this.grid.rowHeight : this.grid.rowHeight; } /** * @hidden * @internal */ isDuplicateOfExistingParent(col, lvl) { const parentCollection = lvl > 0 ? this.columnDimensionsByLevel[lvl - 1] : []; const duplicate = parentCollection.indexOf(col) !== -1; return duplicate; } /** * @hidden * @internal */ isMultiRow(col, lvl) { const isLeaf = !col.columnGroup; return isLeaf && lvl !== this.totalDepth - 1; } /** * @hidden * @internal */ populateColumnDimensionsByLevel() { const res = []; for (let i = 0; i < this.totalDepth; i++) { res[i] = []; } const cols = this.unpinnedColumnCollection; // populate column dimension matrix recursively this.populateDimensionRecursively(cols.filter(x => x.level === 0), 0, res); this.columnDimensionsByLevel = res; } populateDimensionRecursively(currentLevelColumns, level = 0, res) { currentLevelColumns.forEach(col => { if (res[level]) { res[level].push(col); if (col.columnGroup && col.children.length > 0) { const visibleColumns = col.children.toArray().filter(x => !x.hidden); this.populateDimensionRecursively(visibleColumns, level + 1, res); } else if (level < this.totalDepth - 1) { for (let i = level + 1; i <= this.totalDepth - 1; i++) { res[i].push(col); } } } }); } /** * @hidden * @internal */ ngOnChanges(changes) { if (changes.unpinnedColumnCollection) { this.populateColumnDimensionsByLevel(); } } /** * @hidden * @internal */ onDimDragStart(event, area) { this.cdr.detectChanges(); for (const chip of this.notificationChips) { const parent = chip.nativeElement.parentElement; if (area.chipsList.toArray().indexOf(chip) === -1 && parent.children.length > 0 && parent.children.item(0).id !== 'empty') { chip.nativeElement.hidden = false; parent.parentElement.scrollTo({ left: chip.nativeElement.offsetLeft }); } } } /** * @hidden * @internal */ onDimDragEnd() { for (const chip of this.notificationChips) { chip.nativeElement.hidden = true; } } /** * @hidden * @internal */ getAreaHeight(area) { const chips = area.chipsList; return chips && chips.length > 0 ? chips.first.nativeElement.offsetHeight : 0; } /** * @hidden * @internal */ rowRemoved(event) { const row = this.grid.pivotConfiguration.rows.find(x => x.memberName === event.owner.id); this.grid.toggleDimension(row); } /** * @hidden * @internal */ columnRemoved(event) { const col = this.grid.pivotConfiguration.columns.find(x => x.memberName === event.owner.id); this.grid.toggleDimension(col); } /** * @hidden * @internal */ valueRemoved(event) { const value = this.grid.pivotConfiguration.values.find(x => x.member === event.owner.id || x.displayName === event.owner.id); this.grid.toggleValue(value); } /** * @hidden * @internal */ filterRemoved(event) { const filter = this.grid.pivotConfiguration.filters.find(x => x.memberName === event.owner.id); this.grid.toggleDimension(filter); if (this.filterDropdownDimensions.size > 0) { this.onFiltersAreaDropdownClick({ target: this.filtersButton.el.nativeElement }, undefined, false); } else { this.grid.filteringService.hideESF(); } } onFiltersSelectionChanged(event) { this.dropdownChips.chipsList.forEach(chip => { if (chip.id !== event.owner.id) { chip.selected = false; } }); this.onFiltersAreaDropdownClick({ target: this.filtersButton.el.nativeElement }, this.grid.filterDimensions.find(dim => dim.memberName === event.owner.id), false); } /** * @hidden * @internal */ onFilteringIconPointerDown(event) { event.stopPropagation(); event.preventDefault(); } /** * @hidden * @internal */ onFilteringIconClick(event, dimension) { event.stopPropagation(); event.preventDefault(); const dim = dimension; const col = this.grid.dimensionDataColumns.find(x => x.field === dim.memberName || x.field === dim.member); this.grid.filteringService.toggleFilterDropdown(event.target, col); } /** * @hidden * @internal */ onSummaryClick(eventArgs, value, dropdown, chip) { this._subMenuOverlaySettings.target = eventArgs.currentTarget; this.updateDropDown(value, dropdown, chip); } /** * @hidden @internal */ onFiltersAreaDropdownClick(event, dimension, shouldReattach = true) { const dim = dimension || this.filterDropdownDimensions.values().next().value; const col = this.grid.dimensionDataColumns.find(x => x.field === dim.memberName || x.field === dim.member); if (shouldReattach) { this.dropdownChips.chipsList.forEach(chip => { chip.selected = false; }); this.dropdownChips.chipsList.first.selected = true; } this.grid.filteringService.toggleFiltersESF(this.esf, event.target, col, shouldReattach); } /** * @hidden * @internal */ onAggregationChange(event) { if (!this.isSelected(event.newSelection.value)) { this.value.aggregate = event.newSelection.value; const isSingleValue = this.grid.values.length === 1; PivotUtil.updateColumnTypeByAggregator(this.grid.columns, this.value, isSingleValue); this.grid.pipeTrigger++; } } /** * @hidden * @internal */ isSelected(val) { return this.value.aggregate.key === val.key; } /** * @hidden * @internal */ onChipSort(_event, dimension) { if (dimension.sortable === undefined || dimension.sortable) { const startDirection = dimension.sortDirection || SortingDirection.None; const direction = startDirection + 1 > SortingDirection.Desc ? SortingDirection.None : startDirection + 1; this.grid.sortDimension(dimension, direction); } } /** * @hidden * @internal */ onDimDragOver(event, dimension) { if (!event.dragChip || !event.dragChip.data?.pivotArea) return; const typeMismatch = dimension !== undefined ? this.grid.pivotConfiguration.values.find(x => x.member === event.dragChip.id || x.displayName === event.dragChip.id) : !this.grid.pivotConfiguration.values.find(x => x.member === event.dragChip.id || x.displayName === event.dragChip.id); if (typeMismatch) { // cannot drag between dimensions and value return; } // if we are in the left half of the chip, drop on the left // else drop on the right of the chip const clientRect = event.owner.nativeElement.getBoundingClientRect(); const pos = clientRect.width / 2; this._dropPos = event.originalEvent.offsetX > pos ? DropPosition.AfterDropTarget : DropPosition.BeforeDropTarget; if (this._dropPos === DropPosition.AfterDropTarget) { event.owner.nativeElement.previousElementSibling.style.visibility = 'hidden'; event.owner.nativeElement.nextElementSibling.style.visibility = ''; } else { event.owner.nativeElement.nextElementSibling.style.visibility = 'hidden'; event.owner.nativeElement.previousElementSibling.style.visibility = ''; } } /** * @hidden * @internal */ onDimDragLeave(event) { event.owner.nativeElement.previousElementSibling.style.visibility = 'hidden'; event.owner.nativeElement.nextElementSibling.style.visibility = 'hidden'; this._dropPos = DropPosition.AfterDropTarget; } /** * @hidden * @internal */ onAreaDragLeave(event, area) { const dataChips = area.chipsList.toArray().filter(x => this.notificationChips.toArray().indexOf(x) === -1); dataChips.forEach(element => { if (element.nativeElement.previousElementSibling) { element.nativeElement.previousElementSibling.style.visibility = 'hidden'; } if (element.nativeElement.nextElementSibling) { element.nativeElement.nextElementSibling.style.visibility = 'hidden'; } }); } /** * @hidden * @internal */ onValueDrop(event, area) { if (!(event.dragChip && event.dragChip.data?.pivotArea) && !(event.dragData?.chip && !!event.dragData.chip.data.pivotArea)) return; //values can only be reordered const values = this.grid.pivotConfiguration.values; const dragId = event.dragChip?.id || event.dragData?.chip.id; const chipsArray = area.chipsList.toArray(); let chipIndex = chipsArray.indexOf(event.owner) !== -1 ? chipsArray.indexOf(event.owner) : chipsArray.length; chipIndex = this._dropPos === DropPosition.AfterDropTarget ? chipIndex + 1 : chipIndex; const value = values.find(x => x.member === dragId || x.displayName === dragId); if (value) { const dragChipIndex = chipsArray.indexOf(event.dragChip || event.dragData.chip); this.grid.moveValue(value, dragChipIndex >= chipIndex ? chipIndex : chipIndex - 1); } } /** * @hidden * @internal */ onDimDrop(event, area, dimensionType) { if (!(event.dragChip && event.dragChip.data?.pivotArea) && !(event.dragData?.chip && !!event.dragData.chip.data.pivotArea)) return; const dragId = event.dragChip?.id || event.dragData?.chip.id; const currentDim = this.grid.getDimensionsByType(dimensionType); const chipsArray = area.chipsList.toArray(); const chip = chipsArray.find(x => x.id === dragId); const isNewChip = chip === undefined; const isReorder = event.owner.id !== undefined; //const chipIndex = chipsArray.indexOf(event.owner) !== -1 ? chipsArray.indexOf(event.owner) : chipsArray.length; const chipIndex = currentDim.findIndex(x => x.memberName === event.owner.id) !== -1 ? currentDim.findIndex(x => x.memberName === event.owner.id) : currentDim.length; const targetIndex = this._dropPos === DropPosition.AfterDropTarget ? chipIndex + 1 : chipIndex; if (isNewChip) { // chip moved from an external collection const dim = this.grid.allDimensions.find(x => x && x.memberName === dragId); if (!dim) { // you have dragged something that is not a dimension return; } this.grid.moveDimension(dim, dimensionType, targetIndex); } else if (isReorder) { // chip from same collection, reordered. const newDim = currentDim.find(x => x.memberName === dragId); const dragChipIndex = currentDim.findIndex(x => x.memberName === dragId); this.grid.moveDimension(newDim, dimensionType, dragChipIndex > chipIndex ? targetIndex : targetIndex - 1); } this.grid.pipeTrigger++; this.grid.dimensionsChange.emit({ dimensions: currentDim, dimensionCollectionType: dimensionType }); // clean states this.onDimDragEnd(); this.onAreaDragLeave(event, area); } updateDropDown(value, dropdown, chip) { this.value = value; dropdown.width = chip.nativeElement.clientWidth + 'px'; this.aggregateList = PivotUtil.getAggregateList(value, this.grid); this.cdr.detectChanges(); dropdown.open(this._subMenuOverlaySettings); } getRowDimensionColumn(dim) { return this.grid.dimensionDataColumns ? this.grid.dimensionDataColumns.find((col) => col.field === dim.memberName) : null; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.2", ngImport: i0, type: IgxPivotHeaderRowComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.2", type: IgxPivotHeaderRowComponent, isStandalone: true, selector: "igx-pivot-header-row", host: { properties: { "attr.aria-activedescendant": "this.activeDescendant" } }, viewQueries: [{ propertyName: "esf", first: true, predicate: ["esf"], descendants: true }, { propertyName: "filterArea", first: true, predicate: ["filterAreaHidden"], descendants: true }, { propertyName: "filtersButton", first: true, predicate: ["filterIcon"], descendants: true }, { propertyName: "dropdownChips", first: true, predicate: ["dropdownChips"], descendants: true }, { propertyName: "pivotFilterContainer", first: true, predicate: ["pivotFilterContainer"], descendants: true }, { propertyName: "pivotRowContainer", first: true, predicate: ["pivotRowContainer"], descendants: true }, { propertyName: "notificationChips", predicate: ["notifyChip"], descendants: true }, { propertyName: "headerContainers", predicate: ["headerVirtualContainer"], descendants: true, read: IgxGridForOfDirective }, { propertyName: "rowDimensionHeaders", predicate: ["rowDimensionHeaders"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<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