UNPKG

ngx-mat-multi-sort

Version:

An extension for the angular material table to support multi-sorting.

632 lines (621 loc) 39.6 kB
import * as i0 from '@angular/core'; import { Directive, Input, Optional, Inject, ChangeDetectionStrategy, ViewEncapsulation, Component, ContentChild, ViewChild, NgModule } from '@angular/core'; import * as i1 from '@angular/material/sort'; import { MatSort, MatSortHeader, matSortAnimations } from '@angular/material/sort'; import * as i3 from '@angular/cdk/a11y'; import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle, DragDropModule } from '@angular/cdk/drag-drop'; import * as i1$1 from '@angular/cdk/overlay'; import { BlockScrollStrategy } from '@angular/cdk/overlay'; import { TemplatePortal } from '@angular/cdk/portal'; import * as i2 from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatChipSet, MatChipRow, MatChipsModule } from '@angular/material/chips'; import { NgTemplateOutlet, CommonModule } from '@angular/common'; import { MatTooltip, MatTooltipModule } from '@angular/material/tooltip'; import { MatIcon, MatIconModule } from '@angular/material/icon'; import * as i3$1 from '@angular/forms'; import { FormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCommonModule } from '@angular/material/core'; import { MatDividerModule } from '@angular/material/divider'; import { MatMenuModule } from '@angular/material/menu'; import { MatDialogModule } from '@angular/material/dialog'; import { Subject, BehaviorSubject, delay, filter, tap } from 'rxjs'; import { DataSource } from '@angular/cdk/collections'; class MatMultiSort extends MatSort { constructor() { super(...arguments); this.start = 'asc'; this.actives = []; this.directions = []; } ngOnInit() { super.ngOnInit(); } sort(sortable) { this.updateMultipleSorts(sortable); super.sort(sortable); } updateMultipleSorts(sortable) { const i = this.actives.findIndex(activeId => activeId === sortable.id); if (this.isActive(sortable)) { if (this.activeDirection(sortable) === (sortable.start ? sortable.start : this.start)) { this.directions.splice(i, 1, this.getNextSortDirection(sortable)); } else { this.actives.splice(i, 1); this.directions.splice(i, 1); } } else { this.actives.push(sortable.id); this.directions.push(sortable.start ? sortable.start : this.start); } } isActive(sortable) { const i = this.actives.findIndex(activeId => activeId === sortable.id); return i > -1; } activeDirection(sortable) { const i = this.actives.findIndex(activeId => activeId === sortable.id); return this.directions[i] || (sortable.start ? sortable.start : this.start); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSort, deps: null, target: i0.ɵɵFactoryTarget.Directive }); } static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.4", type: MatMultiSort, isStandalone: true, selector: "[matMultiSort]", exportAs: ["matMultiSort"], usesInheritance: true, ngImport: i0 }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSort, decorators: [{ type: Directive, args: [{ selector: '[matMultiSort]', exportAs: 'matMultiSort' }] }] }); class MatMultiSortHeaderComponent extends MatSortHeader { constructor(_intl, changeDetectorRef, _sort, _columnDef, _focusMonitor, _elementRef) { super(_intl, changeDetectorRef, _sort, _columnDef, _focusMonitor, _elementRef); this._intl = _intl; this._sort = _sort; this._columnDef = _columnDef; this.start = 'asc'; this._disableViewStateAnimation = false; } _isSorted() { return this._sort.actives.findIndex(activeId => activeId === this.id) > -1; } _sortId() { return this._sort.actives.findIndex(activeId => activeId === this.id) + 1; } _renderArrow() { return !this._isDisabled() || this._isSorted(); } getSortDirection() { const i = this._sort.actives.findIndex(activeIds => activeIds === this.id); const direction = this._sort.directions[i]; return this._isSorted() ? direction : (this.start || this._sort.start); } _getArrowViewState() { return undefined; } _getArrowDirectionState() { return undefined; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSortHeaderComponent, deps: [{ token: i1.MatSortHeaderIntl }, { token: i0.ChangeDetectorRef }, { token: MatMultiSort, optional: true }, { token: 'C2_SORT_HEADER_COLUMN_DEF', optional: true }, { token: i3.FocusMonitor }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: MatMultiSortHeaderComponent, isStandalone: true, selector: "[mat-multi-sort-header]", inputs: { id: ["mat-multi-sort-header", "id"] }, providers: [{ provide: MatSort, useExisting: MatMultiSort }], exportAs: ["matMultiSortHeader"], usesInheritance: true, ngImport: i0, template: "<div class=\"mat-sort-header-container\"\n [class.mat-sort-header-sorted]=\"_isSorted()\"\n [class.mat-sort-header-position-before]=\"arrowPosition === 'before'\"\n [class.mat-sort-header-ascending]=\"getSortDirection() === 'asc'\"\n [class.mat-sort-header-deascending]=\"getSortDirection() === 'desc'\">\n\n <div class=\"mat-sort-header-content\">\n <ng-content></ng-content>\n </div>\n <!-- Disable animations while a current animation is running -->\n @if (_renderArrow() && _isSorted()) {\n <div class=\"mat-sort-header-arrow\"\n [@arrowOpacity]=\"_getArrowViewState()\"\n [@arrowPosition]=\"_getArrowViewState()\"\n [@allowChildren]=\"_getArrowDirectionState()\"\n (@arrowPosition.start)=\"_disableViewStateAnimation = true\"\n (@arrowPosition.done)=\"_disableViewStateAnimation = false\">\n <svg [class.asc]=\"getSortDirection() === 'asc'\"\n [class.desc]=\"getSortDirection() === 'desc'\"\n viewBox=\"0 -960 960 960\" focusable=\"false\" aria-hidden=\"true\">\n <path d=\"M440-240v-368L296-464l-56-56 240-240 240 240-56 56-144-144v368h-80Z\"></path>\n </svg>\n </div>\n }\n @if (_isSorted()) {\n <div>{{_sortId()}}</div>\n }\n</div>\n", styles: [".mat-sort-header-container{display:flex;cursor:pointer;align-items:center}.mat-sort-header-disabled .mat-sort-header-container{cursor:default}.mat-sort-header-position-before{flex-direction:row-reverse}.mat-sort-header-content{text-align:center;display:flex;align-items:center}.mat-sort-header-arrow{height:12px;width:12px;min-width:12px;position:relative;display:flex}.mat-sort-header-arrow svg{width:24px;height:24px;position:absolute;top:50%;left:50%;transform:translate(-50%) translateY(-50%);transform-origin:top left}.mat-sort-header-arrow svg.asc{rotate:0}.mat-sort-header-arrow svg.desc{rotate:180deg}.mat-sort-header-arrow,[dir=rtl] .mat-sort-header-position-before .mat-sort-header-arrow{margin:0 0 0 6px}.mat-sort-header-position-before .mat-sort-header-arrow,[dir=rtl] .mat-sort-header-arrow{margin:0 6px 0 0}\n"], animations: [ matSortAnimations.indicator, matSortAnimations.leftPointer, matSortAnimations.rightPointer, matSortAnimations.arrowOpacity, matSortAnimations.arrowPosition, matSortAnimations.allowChildren ], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSortHeaderComponent, decorators: [{ type: Component, args: [{ selector: '[mat-multi-sort-header]', exportAs: 'matMultiSortHeader', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [], animations: [ matSortAnimations.indicator, matSortAnimations.leftPointer, matSortAnimations.rightPointer, matSortAnimations.arrowOpacity, matSortAnimations.arrowPosition, matSortAnimations.allowChildren ], providers: [{ provide: MatSort, useExisting: MatMultiSort }], template: "<div class=\"mat-sort-header-container\"\n [class.mat-sort-header-sorted]=\"_isSorted()\"\n [class.mat-sort-header-position-before]=\"arrowPosition === 'before'\"\n [class.mat-sort-header-ascending]=\"getSortDirection() === 'asc'\"\n [class.mat-sort-header-deascending]=\"getSortDirection() === 'desc'\">\n\n <div class=\"mat-sort-header-content\">\n <ng-content></ng-content>\n </div>\n <!-- Disable animations while a current animation is running -->\n @if (_renderArrow() && _isSorted()) {\n <div class=\"mat-sort-header-arrow\"\n [@arrowOpacity]=\"_getArrowViewState()\"\n [@arrowPosition]=\"_getArrowViewState()\"\n [@allowChildren]=\"_getArrowDirectionState()\"\n (@arrowPosition.start)=\"_disableViewStateAnimation = true\"\n (@arrowPosition.done)=\"_disableViewStateAnimation = false\">\n <svg [class.asc]=\"getSortDirection() === 'asc'\"\n [class.desc]=\"getSortDirection() === 'desc'\"\n viewBox=\"0 -960 960 960\" focusable=\"false\" aria-hidden=\"true\">\n <path d=\"M440-240v-368L296-464l-56-56 240-240 240 240-56 56-144-144v368h-80Z\"></path>\n </svg>\n </div>\n }\n @if (_isSorted()) {\n <div>{{_sortId()}}</div>\n }\n</div>\n", styles: [".mat-sort-header-container{display:flex;cursor:pointer;align-items:center}.mat-sort-header-disabled .mat-sort-header-container{cursor:default}.mat-sort-header-position-before{flex-direction:row-reverse}.mat-sort-header-content{text-align:center;display:flex;align-items:center}.mat-sort-header-arrow{height:12px;width:12px;min-width:12px;position:relative;display:flex}.mat-sort-header-arrow svg{width:24px;height:24px;position:absolute;top:50%;left:50%;transform:translate(-50%) translateY(-50%);transform-origin:top left}.mat-sort-header-arrow svg.asc{rotate:0}.mat-sort-header-arrow svg.desc{rotate:180deg}.mat-sort-header-arrow,[dir=rtl] .mat-sort-header-position-before .mat-sort-header-arrow{margin:0 0 0 6px}.mat-sort-header-position-before .mat-sort-header-arrow,[dir=rtl] .mat-sort-header-arrow{margin:0 6px 0 0}\n"] }] }], ctorParameters: () => [{ type: i1.MatSortHeaderIntl }, { type: i0.ChangeDetectorRef }, { type: MatMultiSort, decorators: [{ type: Optional }] }, { type: undefined, decorators: [{ type: Inject, args: ['C2_SORT_HEADER_COLUMN_DEF'] }, { type: Optional }] }, { type: i3.FocusMonitor }, { type: i0.ElementRef }], propDecorators: { id: [{ type: Input, args: ['mat-multi-sort-header'] }] } }); class MatMultiSortTableSettingsComponent { set tableData(tableData) { this._tableData = tableData; } constructor(overlay, viewContainerRef, viewportRuler) { this.overlay = overlay; this.viewContainerRef = viewContainerRef; this.viewportRuler = viewportRuler; this.sort = []; this.sortToolTip = ''; this.closeDialogOnChoice = true; this.scrollStrategy = new BlockScrollStrategy(this.viewportRuler, document); this.disableSortIndicators = false; } ngOnInit() { this.sort = this.getSort(); this._tableData.sortObservable.subscribe(() => this.sort = this.getSort()); this._tableData.onColumnsChange().subscribe(() => this.sort = this.getSort()); } openDialog() { const button = this.buttonRef.nativeElement; const positionStrategyBuilder = this.overlay.position(); const positionStrategy = positionStrategyBuilder .flexibleConnectedTo(button) .withFlexibleDimensions(true) .withViewportMargin(10) .withGrowAfterOpen(true) .withPush(true) .withPositions([{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top' }]); this.overlayRef = this.overlay.create({ hasBackdrop: true, backdropClass: 'cdk-overlay-transparent-backdrop', panelClass: 'column-overlay', positionStrategy, scrollStrategy: this.scrollStrategy }); const templatePortal = new TemplatePortal(this.templateRef, this.viewContainerRef); this.overlayRef.attach(templatePortal); this.overlayRef.backdropClick().subscribe(() => { this.overlayRef.dispose(); }); } drop(event) { moveItemInArray(this._tableData.columns, event.previousIndex, event.currentIndex); this._tableData.displayedColumns = this._tableData.columns.filter(c => c.isActive).map(c => c.id); this._tableData.storeTableSettings(); } toggle() { this._tableData.displayedColumns = this._tableData.columns.filter(c => { if (!c.isActive) { this.sort = this.sort.filter(s => s.id !== c.id); } return c.isActive; }).map(c => c.id); this.updateSort(); if (this.closeDialogOnChoice) { this.overlayRef.dispose(); } } dropSort(event) { moveItemInArray(this.sort, event.previousIndex, event.currentIndex); this.updateSort(); } getSort() { const sorting = []; for (let i = 0; i < this._tableData.sortParams.length; i++) { sorting.push({ id: this._tableData.sortParams[i], name: this._tableData.columns.find(c => c.id === this._tableData.sortParams[i])?.name ?? '', direction: this._tableData.sortDirs[i] }); } return sorting; } remove(id) { this.sort = this.sort.filter(v => v.id !== id); this.updateSort(); } updateDirection(id) { const i = this.sort.findIndex(v => v.id === id); if (this.sort[i].direction === 'asc') { this.sort[i].direction = 'desc'; } else { this.sort[i].direction = 'asc'; } this.updateSort(); } updateSort() { this._tableData.sortParams = this.sort.map(v => v.id); this._tableData.sortDirs = this.sort.map(v => v.direction); this._tableData.updateSortHeaders(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSortTableSettingsComponent, deps: [{ token: i1$1.Overlay }, { token: i0.ViewContainerRef }, { token: i1$1.ViewportRuler }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: MatMultiSortTableSettingsComponent, isStandalone: true, selector: "mat-multi-sort-table-settings", inputs: { sortToolTip: "sortToolTip", closeDialogOnChoice: "closeDialogOnChoice", scrollStrategy: "scrollStrategy", tableData: "tableData", disableSortIndicators: "disableSortIndicators" }, queries: [{ propertyName: "sortIndicatorRef", first: true, predicate: ["sortIndicator"], descendants: true }], viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["templateRef"], descendants: true, static: true }, { propertyName: "buttonRef", first: true, predicate: ["settingsMenu"], descendants: true }], ngImport: i0, template: "<div class=\"table-settings\">\n <div class=\"table-settings-sort\">\n <mat-chip-set class=\"drag-chip-list\" cdkDropList cdkDropListOrientation='horizontal'\n (cdkDropListDropped)=\"dropSort($event)\" [disabled]=\"disableSortIndicators\">\n @for (item of sort; track item) {\n <mat-chip-row class=\"drag-chip\" cdkDrag (removed)=\"remove(item.id)\"\n (click)=\"updateDirection(item.id)\">\n <div class=\"chip-content\">\n @if (sortIndicatorRef) {\n <ng-container\n [ngTemplateOutlet]=\"sortIndicatorRef\"\n [ngTemplateOutletContext]=\"{direction:item.direction, columnName: item.name }\">\n </ng-container>\n } @else {\n <div>\n {{item.name}}:\n <div class=\"sorting\" [matTooltip]=\"sortToolTip\">\n {{item.direction}}\n </div>\n </div>\n }\n <mat-icon class=\"mat-mdc-chip-trailing-icon\" (click)=\"remove(item.id)\">cancel</mat-icon>\n </div>\n </mat-chip-row>\n }\n </mat-chip-set>\n </div>\n <div style=\"flex: 1 1 auto;\"></div>\n <div #settingsMenu (click)=\"openDialog()\" class=\"table-settings-menu\">\n <ng-content #menuRef></ng-content>\n </div>\n</div>\n\n<ng-template #templateRef>\n <div cdkDropList class=\"column-list\" (cdkDropListDropped)=\"drop($event)\">\n @for (column of _tableData.columns; track column) {\n <div class=\"column-item\" cdkDrag>\n <mat-icon cdkDragHandle>drag_indicator</mat-icon>\n <mat-checkbox [(ngModel)]=\"column.isActive\" (change)=\"toggle()\">{{column.name}}</mat-checkbox>\n </div>\n }\n </div>\n</ng-template>\n", styles: [".table-settings{display:flex}.table-settings .table-settings-menu{margin:8px 16px}.table-settings-sort{margin:auto 0}.chip-content{display:flex;align-items:center}.chip-content mat-icon{opacity:.6}.sorting{display:inline-block;margin:0 6px}.sorting:hover{cursor:pointer}.drag-chip{border:solid 1px rgba(0,0,0,.12);background-color:#fff}.drag-chip:hover{cursor:move;background-color:#fff}.drag-chip:hover:after{opacity:0}.drag-chip:focus:after{opacity:0}.drag-chip-list.cdk-drop-list-dragging .drag-chip:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.column-list{max-height:70vh;overflow:auto;border-radius:4px;padding:1rem;box-shadow:0 11px 15px -7px #0003,0 24px 38px 3px #00000024,0 9px 46px 8px #0000001f;background-color:#fff;color:#000000de}.column-item{height:48px;display:flex;justify-content:flex-start;align-items:center;margin:1px;padding:0 16px 0 8px}.column-item mat-icon{margin-right:16px}.column-item mat-checkbox{line-height:48px;color:#000000de;font-size:14px;font-weight:400}.column-item>mat-icon:hover{cursor:grab;border-top:solid 1px rgba(0,0,0,.12);border-bottom:solid 1px rgba(0,0,0,.12)}.cdk-drag-preview{box-sizing:border-box;border-radius:var(--mat-chip-container-shape-radius, 8px);box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;overflow:hidden}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.column-item:last-child{border:none}.column-list.cdk-drop-list-dragging .column-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "component", type: MatChipRow, selector: "mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]", inputs: ["editable"], outputs: ["edited"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSortTableSettingsComponent, decorators: [{ type: Component, args: [{ selector: 'mat-multi-sort-table-settings', imports: [MatCheckboxModule, CdkDropList, NgTemplateOutlet, MatTooltip, MatIcon, CdkDrag, CdkDragHandle, FormsModule, MatChipSet, MatChipRow], template: "<div class=\"table-settings\">\n <div class=\"table-settings-sort\">\n <mat-chip-set class=\"drag-chip-list\" cdkDropList cdkDropListOrientation='horizontal'\n (cdkDropListDropped)=\"dropSort($event)\" [disabled]=\"disableSortIndicators\">\n @for (item of sort; track item) {\n <mat-chip-row class=\"drag-chip\" cdkDrag (removed)=\"remove(item.id)\"\n (click)=\"updateDirection(item.id)\">\n <div class=\"chip-content\">\n @if (sortIndicatorRef) {\n <ng-container\n [ngTemplateOutlet]=\"sortIndicatorRef\"\n [ngTemplateOutletContext]=\"{direction:item.direction, columnName: item.name }\">\n </ng-container>\n } @else {\n <div>\n {{item.name}}:\n <div class=\"sorting\" [matTooltip]=\"sortToolTip\">\n {{item.direction}}\n </div>\n </div>\n }\n <mat-icon class=\"mat-mdc-chip-trailing-icon\" (click)=\"remove(item.id)\">cancel</mat-icon>\n </div>\n </mat-chip-row>\n }\n </mat-chip-set>\n </div>\n <div style=\"flex: 1 1 auto;\"></div>\n <div #settingsMenu (click)=\"openDialog()\" class=\"table-settings-menu\">\n <ng-content #menuRef></ng-content>\n </div>\n</div>\n\n<ng-template #templateRef>\n <div cdkDropList class=\"column-list\" (cdkDropListDropped)=\"drop($event)\">\n @for (column of _tableData.columns; track column) {\n <div class=\"column-item\" cdkDrag>\n <mat-icon cdkDragHandle>drag_indicator</mat-icon>\n <mat-checkbox [(ngModel)]=\"column.isActive\" (change)=\"toggle()\">{{column.name}}</mat-checkbox>\n </div>\n }\n </div>\n</ng-template>\n", styles: [".table-settings{display:flex}.table-settings .table-settings-menu{margin:8px 16px}.table-settings-sort{margin:auto 0}.chip-content{display:flex;align-items:center}.chip-content mat-icon{opacity:.6}.sorting{display:inline-block;margin:0 6px}.sorting:hover{cursor:pointer}.drag-chip{border:solid 1px rgba(0,0,0,.12);background-color:#fff}.drag-chip:hover{cursor:move;background-color:#fff}.drag-chip:hover:after{opacity:0}.drag-chip:focus:after{opacity:0}.drag-chip-list.cdk-drop-list-dragging .drag-chip:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.column-list{max-height:70vh;overflow:auto;border-radius:4px;padding:1rem;box-shadow:0 11px 15px -7px #0003,0 24px 38px 3px #00000024,0 9px 46px 8px #0000001f;background-color:#fff;color:#000000de}.column-item{height:48px;display:flex;justify-content:flex-start;align-items:center;margin:1px;padding:0 16px 0 8px}.column-item mat-icon{margin-right:16px}.column-item mat-checkbox{line-height:48px;color:#000000de;font-size:14px;font-weight:400}.column-item>mat-icon:hover{cursor:grab;border-top:solid 1px rgba(0,0,0,.12);border-bottom:solid 1px rgba(0,0,0,.12)}.cdk-drag-preview{box-sizing:border-box;border-radius:var(--mat-chip-container-shape-radius, 8px);box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;overflow:hidden}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.column-item:last-child{border:none}.column-list.cdk-drop-list-dragging .column-item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}\n"] }] }], ctorParameters: () => [{ type: i1$1.Overlay }, { type: i0.ViewContainerRef }, { type: i1$1.ViewportRuler }], propDecorators: { templateRef: [{ type: ViewChild, args: ['templateRef', { static: true }] }], buttonRef: [{ type: ViewChild, args: ['settingsMenu'] }], sortIndicatorRef: [{ type: ContentChild, args: ['sortIndicator', { static: false }] }], sortToolTip: [{ type: Input }], closeDialogOnChoice: [{ type: Input }], scrollStrategy: [{ type: Input }], tableData: [{ type: Input }], disableSortIndicators: [{ type: Input }] } }); class MatMultiSortModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSortModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSortModule, imports: [CommonModule, MatCommonModule, MatDividerModule, DragDropModule, MatIconModule, MatCheckboxModule, MatMenuModule, MatButtonModule, FormsModule, MatChipsModule, MatTooltipModule, MatDialogModule, MatMultiSort, MatMultiSortHeaderComponent, MatMultiSortTableSettingsComponent] }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSortModule, imports: [CommonModule, MatCommonModule, MatDividerModule, DragDropModule, MatIconModule, MatCheckboxModule, MatMenuModule, MatButtonModule, FormsModule, MatChipsModule, MatTooltipModule, MatDialogModule, MatMultiSortTableSettingsComponent] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MatMultiSortModule, decorators: [{ type: NgModule, args: [{ declarations: [], exports: [], imports: [ CommonModule, MatCommonModule, MatDividerModule, DragDropModule, MatIconModule, MatCheckboxModule, MatMenuModule, MatButtonModule, FormsModule, MatChipsModule, MatTooltipModule, MatDialogModule, MatMultiSort, MatMultiSortHeaderComponent, MatMultiSortTableSettingsComponent ] }] }] }); class Settings { constructor(key) { this._key = key; this._columns = []; this._sortParams = []; this._sortDirs = []; } load() { const storedValue = localStorage.getItem(this._key); const value = storedValue ? JSON.parse(storedValue) : undefined; if (value) { this._columns = value._columns || []; this._sortDirs = value._sortDirs || []; this._sortParams = value._sortParams || []; } } save() { const settingsString = JSON.stringify(this); localStorage.setItem(this._key, settingsString); } get columns() { return this._columns; } get sortParams() { return this._sortParams; } get sortDirs() { return this._sortDirs; } get key() { return this._key; } set columns(columns) { this._columns = columns; } set sortParams(sortParams) { this._sortParams = sortParams; } set sortDirs(sortDirs) { this._sortDirs = sortDirs; } } class TableData { // TODO refactor constructor(columns, options) { this._displayedColumns = []; this.pageSize = 0; this.pageIndex = 0; this._totalElements = 0; this._key = ''; this._nextObservable = new Subject(); this._previousObservable = new Subject(); this._sizeObservable = new Subject(); this._sortObservable = new Subject(); this._sortHeadersObservable = new Subject(); this._columns = new BehaviorSubject(columns.map(c => { if (c.isActive === undefined) { c.isActive = true; } return c; })); if (options) { if (options.pageSizeOptions && options.pageSizeOptions.length < 1) { throw Error('Array of pageSizeOptions must contain at least one entry'); } if (options.defaultSortParams) { options.defaultSortParams.map(s => { if (this._columns.value.find(column => column.id === s) === undefined) { throw Error(`Provided sort parameter "${s}" is not a column.`); } }); } this._sortParams = options.defaultSortParams || []; this._sortDirs = options.defaultSortDirs || []; if (this._sortParams.length !== this._sortDirs.length) { this._sortDirs = this._sortParams.map(() => 'asc'); } this._totalElements = options.totalElements || 0; this._pageSizeOptions = options.pageSizeOptions || [10, 20, 50, 100]; this._key = options.localStorageKey ?? ''; } else { this._pageSizeOptions = [10, 20, 50, 100]; this._sortParams = []; this._sortDirs = []; } this.init(); } onSortEvent() { this._sortParams = this._dataSource.sort['actives']; this._sortDirs = this._dataSource.sort['directions']; this._clientSideSort(); this._sortObservable.next(); this.storeTableSettings(); } onPaginationEvent($event) { const tmpPageSize = this.pageSize; this.pageSize = $event.pageSize; this.pageIndex = $event.pageIndex; if (tmpPageSize !== this.pageSize) { this._sizeObservable.next(); } else if ($event.previousPageIndex !== undefined && $event.previousPageIndex < $event.pageIndex) { this._nextObservable.next(); } else if ($event.previousPageIndex !== undefined && $event.previousPageIndex > $event.pageIndex) { this._previousObservable.next(); } } updateSortHeaders() { // Dirty hack to display default sort column(s) const temp = Object.assign([], this._displayedColumns); this._sortHeadersObservable.next([]); this._sortHeadersObservable.next(temp); this._clientSideSort(); this._sortObservable.next(); this.storeTableSettings(); } // this fixes an infine loop of rerendering subscribeSortHeaders() { this._sortHeadersObservable.pipe(delay(0), // ignore when there is no update in the sort (params or dirs) filter(() => this._displayedSortDirs !== this.sortDirs && this._displayedSortParams !== this.sortParams), tap((column) => { // update the displayed sort when it is not the empty array if (column.length > 0) { this._displayedSortDirs = this.sortDirs; this._displayedSortParams = this.sortParams; } })).subscribe(columns => this._displayedColumns = columns); } init() { this.subscribeSortHeaders(); if (this._key) { const settings = new Settings(this._key); settings.load(); if (this._isLocalStorageSettingsValid(settings)) { // load column configuration from localstorage and update the name this.columns = settings.columns.map(storedColumn => { return { ...storedColumn, name: this.columns.find(column => column.id === storedColumn.id)?.name ?? storedColumn.name }; }); this._sortDirs = settings.sortDirs; this._sortParams = settings.sortParams; } else { console.warn("Stored tableSettings are invalid. Using default"); } } this.displayedColumns = this.columns.filter(c => c.isActive).map(c => c.id); } _clientSideSort() { this._dataSource.orderData(); } _isLocalStorageSettingsValid(settings) { // check if number of columns matching if (settings.columns.length !== this._columns.value.length) { return false; } // check if columns are the same for (const column of settings.columns) { const match = this._columns.value.find(c => c.id === column.id); if (match === undefined) { return false; } } return true; } storeTableSettings() { if (this._key) { const settings = new Settings(this._key); settings.columns = this._columns.value; settings.sortParams = this._sortParams; settings.sortDirs = this._sortDirs; settings.save(); } } set totalElements(totalElements) { this._totalElements = totalElements; } get totalElements() { return this._totalElements; } set displayedColumns(displayedColumns) { this._displayedColumns = displayedColumns; this._columns.next(this._columns.value.map(c => { c.isActive = this._displayedColumns.includes(c.id); return c; })); } get displayedColumns() { return this._displayedColumns; } set dataSource(dataSource) { this._dataSource = dataSource; if (this._sortParams.length > 0) { this._dataSource.sort.actives = this._sortParams; this._dataSource.sort.directions = this._sortDirs.map(v => v); this.updateSortHeaders(); } } get dataSource() { return this._dataSource; } set data(data) { this._dataSource.data = data; this._clientSideSort(); } set columns(v) { this._columns.next(v.map(c => { if (c.isActive === undefined) { c.isActive = true; } return c; })); } onColumnsChange() { return this._columns; } updateColumnNames(v) { const dict = {}; v.forEach(c => dict[c.id] = c.name); this._columns.next(this._columns.value.map(c => { c.name = dict[c.id] || c.name; return c; })); } get nextObservable() { return this._nextObservable; } get previousObservable() { return this._previousObservable; } get sizeObservable() { return this._sizeObservable; } get sortObservable() { return this._sortObservable; } get sortParams() { return this._sortParams; } get sortDirs() { return this._sortDirs; } get columns() { return this._columns.value; } get pageSizeOptions() { return this._pageSizeOptions; } set sortParams(v) { this._sortParams = v; this._dataSource.sort.actives = this._sortParams; } set sortDirs(v) { this._sortDirs = v; this._dataSource.sort.directions = this._sortDirs.map(elem => elem); } } class MatMultiSortTableDataSource extends DataSource { constructor(sort, clientSideSorting = false) { super(); this._data = new BehaviorSubject([]); this.sort = sort; this.clientSideSorting = clientSideSorting; } set data(data) { this._data.next(data); } get data() { return this._data.value; } connect() { return this._data; } disconnect() { this._data.complete(); } orderData() { this._data.next(this.sortData(this._data.value, this.sort.actives, this.sort.directions)); } sortData(data, actives, directions) { const _data = Object.assign(new Array(), data); if (this.clientSideSorting) { return _data.sort((i1, i2) => { return this._sortData(i1, i2, actives, directions); }); } return _data; } _sortData(d1, d2, params, dirs) { // @ts-expect-error -- need a typesafe way to express these accessor operations, ts-ignore could be a solution // if there's not a suitable solution offered by typescript if (d1[params[0]] > d2[params[0]]) { return dirs[0] === 'asc' ? 1 : -1; // @ts-expect-error --- same } else if (d1[params[0]] < d2[params[0]]) { return dirs[0] === 'asc' ? -1 : 1; } else { if (params.length > 1) { params = params.slice(1, params.length); dirs = dirs.slice(1, dirs.length); return this._sortData(d1, d2, params, dirs); } else { return 0; } } } } /* * Public API Surface of mat-multi-sort */ /** * Generated bundle index. Do not edit. */ export { MatMultiSort, MatMultiSortHeaderComponent, MatMultiSortModule, MatMultiSortTableDataSource, MatMultiSortTableSettingsComponent, TableData }; //# sourceMappingURL=ngx-mat-multi-sort.mjs.map