@progress/kendo-angular-grid
Version:
Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.
144 lines (143 loc) • 6.65 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { ChangeDetectorRef, Directive, ElementRef, HostBinding, Input, NgZone, Renderer2 } from '@angular/core';
import { Observable } from 'rxjs';
import { resizableColumns } from '../columns/column-common';
import { ColumnResizingService } from './column-resizing.service';
import { filter, tap, map, switchMap, bufferCount } from 'rxjs/operators';
import { ContextService } from '../common/provider.service';
import * as i0 from "@angular/core";
import * as i1 from "./column-resizing.service";
import * as i2 from "../common/provider.service";
/**
* @hidden
*/
const columnsToResize = ({ columns }) => Math.max(1, resizableColumns(columns).filter(c => !c.isColumnGroup).length);
/**
* @hidden
*/
const row = selector => element => element.querySelector(selector);
/**
* @hidden
*/
const headerRow = index => element => element.querySelectorAll('thead>tr')[index];
/**
* @hidden
*/
const cell = (index, selector = 'td') => element => element.querySelectorAll(`${selector}:not(.k-group-cell):not(.k-hierarchy-cell)`)[index];
/**
* @hidden
*/
const offsetWidth = element => element.offsetWidth;
/**
* @hidden
*/
const pipe = (...fns) => data => fns.reduce((state, fn) => state ? fn(state) : 0, data);
/**
* @hidden
*/
export class TableDirective {
element;
renderer;
service;
zone;
cdr;
ctx;
locked = false;
virtualColumns;
get minWidth() {
return this.firstResize ? 0 : null;
}
firstResize = false;
subscription;
autoFitSubscription;
constructor(element, renderer, service, zone, cdr, ctx) {
this.element = element;
this.renderer = renderer;
this.service = service;
this.zone = zone;
this.cdr = cdr;
this.ctx = ctx;
}
ngOnInit() {
const obs = this.service
.changes.pipe(filter(e => this.locked === e.locked));
this.subscription = obs.pipe(filter(e => e.type === 'start'), tap(this.initState.bind(this)), map(columnsToResize), switchMap((take) => obs.pipe(filter(e => e.type === 'resizeTable'), map(e => e.delta), bufferCount(take)))).subscribe(this.resize.bind(this));
this.autoFitSubscription = this.service
.registerTable({
autoFit: this.autoFitObservable.bind(this),
locked: this.locked
});
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
if (this.autoFitSubscription) {
this.autoFitSubscription();
this.autoFitSubscription = null;
}
}
initState() {
this.firstResize = true;
const constrainedWithVirtualColumns = this.ctx.grid?.resizable === 'constrained' && this.virtualColumns;
if ((!this.virtualColumns || this.locked) || constrainedWithVirtualColumns) {
this.service.originalWidth = offsetWidth(this.element.nativeElement);
}
}
resize(deltas) {
const constrainedModeNoShift = this.ctx.grid?.resizable === 'constrained' && !this.service.isShiftPressed;
const unconstrainedModeShift = (this.ctx.grid?.resizable === true || this.ctx.grid?.resizable === 'unconstrained') && this.service.isShiftPressed;
const isConstrainedMode = constrainedModeNoShift || unconstrainedModeShift;
if (isConstrainedMode && !this.service.autoFitResize) {
this.renderer.setStyle(this.element.nativeElement, 'width', this.service.originalWidth + 'px');
}
else {
if (!this.virtualColumns || this.locked) {
const delta = deltas.reduce((sum, item) => sum + item, 0);
const width = this.service.originalWidth + delta;
this.renderer.setStyle(this.element.nativeElement, 'width', width + 'px');
}
}
this.cdr.detectChanges();
}
autoFitObservable(columnInfo) {
return Observable.create(observer => {
this.zone.runOutsideAngular(() => {
this.renderer.addClass(this.element.nativeElement, 'k-autofitting');
this.cdr.detectChanges();
const widths = columnInfo.map(this.measureColumn.bind(this));
this.renderer.removeClass(this.element.nativeElement, 'k-autofitting');
observer.next(widths);
});
});
}
measureColumn(info) {
const dom = this.element.nativeElement;
const header = pipe(headerRow(info.level), cell(info.headerIndex, 'th'), offsetWidth)(dom);
let data = 0;
if (!info.isParentSpan || (info.isParentSpan && info.isLastInSpan)) {
data = pipe(row('tbody>tr:not(.k-grouping-row):not(.k-grid-norecords)'), cell(info.index), offsetWidth)(dom);
}
const footer = pipe(row('tfoot>tr'), cell(info.index), offsetWidth)(dom);
return Math.max(header, data, footer);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TableDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1.ColumnResizingService }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: i2.ContextService }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: TableDirective, isStandalone: true, selector: "[kendoGridResizableTable]", inputs: { locked: "locked", virtualColumns: "virtualColumns" }, host: { properties: { "style.min-width": "this.minWidth" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TableDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoGridResizableTable]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1.ColumnResizingService }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: i2.ContextService }]; }, propDecorators: { locked: [{
type: Input
}], virtualColumns: [{
type: Input
}], minWidth: [{
type: HostBinding,
args: ['style.min-width']
}] } });