@swimlane/ngx-datatable
Version:
ngx-datatable is an Angular table grid component for presenting large and complex data.
933 lines (915 loc) • 335 kB
JavaScript
import * as i0 from '@angular/core';
import { Directive, input, contentChild, TemplateRef, computed, output, inject, InjectionToken, Component, ViewContainerRef, Injector, booleanAttribute, numberAttribute, ElementRef, NgZone, signal, DOCUMENT, Injectable, ChangeDetectionStrategy, KeyValueDiffers, HostListener, linkedSignal, ChangeDetectorRef, HostBinding, Renderer2, model, viewChildren, DestroyRef, effect, untracked, ViewChild, Input, ContentChildren, contentChildren, viewChild, IterableDiffers, ContentChild, NgModule } from '@angular/core';
import { NgTemplateOutlet, NgStyle } from '@angular/common';
import { __decorate } from 'tslib';
import { startWith } from 'rxjs';
class DatatableGroupHeaderTemplateDirective {
static ngTemplateContextGuard(directive, context) {
return true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableGroupHeaderTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: DatatableGroupHeaderTemplateDirective, isStandalone: true, selector: "[ngx-datatable-group-header-template]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableGroupHeaderTemplateDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngx-datatable-group-header-template]'
}]
}] });
class DatatableGroupHeaderDirective {
constructor() {
/**
* Row height is required when virtual scroll is enabled.
*/
this.rowHeight = input(0, ...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
/**
* Show checkbox at group header to select all rows of the group.
*/
this.checkboxable = input(false, ...(ngDevMode ? [{ debugName: "checkboxable" }] : /* istanbul ignore next */ []));
this._templateInput = input(undefined, { ...(ngDevMode ? { debugName: "_templateInput" } : /* istanbul ignore next */ {}), alias: 'template' });
this._templateQuery = contentChild(DatatableGroupHeaderTemplateDirective, { ...(ngDevMode ? { debugName: "_templateQuery" } : /* istanbul ignore next */ {}), read: TemplateRef });
this.template = computed(() => this._templateInput() ?? this._templateQuery() ?? null, ...(ngDevMode ? [{ debugName: "template" }] : /* istanbul ignore next */ []));
/**
* Track toggling of group visibility
*/
this.toggle = output();
}
/**
* Toggle the expansion of a group
*/
toggleExpandGroup(group) {
this.toggle.emit({
type: 'group',
value: group
});
}
/**
* Expand all groups
*/
expandAllGroups() {
this.toggle.emit({
type: 'all',
value: true
});
}
/**
* Collapse all groups
*/
collapseAllGroups() {
this.toggle.emit({
type: 'all',
value: false
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableGroupHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.2.9", type: DatatableGroupHeaderDirective, isStandalone: true, selector: "ngx-datatable-group-header", inputs: { rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: false, transformFunction: null }, checkboxable: { classPropertyName: "checkboxable", publicName: "checkboxable", isSignal: true, isRequired: false, transformFunction: null }, _templateInput: { classPropertyName: "_templateInput", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggle: "toggle" }, queries: [{ propertyName: "_templateQuery", first: true, predicate: DatatableGroupHeaderTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableGroupHeaderDirective, decorators: [{
type: Directive,
args: [{
selector: 'ngx-datatable-group-header'
}]
}], propDecorators: { rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: false }] }], checkboxable: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkboxable", required: false }] }], _templateInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "template", required: false }] }], _templateQuery: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DatatableGroupHeaderTemplateDirective), { ...{
read: TemplateRef
}, isSignal: true }] }], toggle: [{ type: i0.Output, args: ["toggle"] }] } });
/**
* This component is passed as ng-template and rendered by BodyComponent.
* BodyComponent uses rowDefInternal to first inject actual row template.
* This component will render that actual row template.
*/
class DatatableRowDefComponent {
constructor() {
this.rowDef = inject(ROW_DEF_TOKEN);
this.rowContext = {
...this.rowDef.rowDefInternal(),
disabled: this.rowDef.rowDefInternalDisabled()
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableRowDefComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: DatatableRowDefComponent, isStandalone: true, selector: "datatable-row-def", ngImport: i0, template: `@if (rowDef.rowDefInternal().rowTemplate) {
<ng-container
[ngTemplateOutlet]="rowDef.rowDefInternal().rowTemplate"
[ngTemplateOutletContext]="rowContext"
/>
}`, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableRowDefComponent, decorators: [{
type: Component,
args: [{
selector: 'datatable-row-def',
imports: [NgTemplateOutlet],
template: `@if (rowDef.rowDefInternal().rowTemplate) {
<ng-container
[ngTemplateOutlet]="rowDef.rowDefInternal().rowTemplate"
[ngTemplateOutletContext]="rowContext"
/>
}`
}]
}] });
class DatatableRowDefDirective {
static ngTemplateContextGuard(_dir, ctx) {
return true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableRowDefDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: DatatableRowDefDirective, isStandalone: true, selector: "[rowDef]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableRowDefDirective, decorators: [{
type: Directive,
args: [{
selector: '[rowDef]'
}]
}] });
/**
* @internal To be used internally by ngx-datatable.
*/
class DatatableRowDefInternalDirective {
constructor() {
this.vc = inject(ViewContainerRef);
this.rowDefInternal = input.required(...(ngDevMode ? [{ debugName: "rowDefInternal" }] : /* istanbul ignore next */ []));
this.rowDefInternalDisabled = input(...(ngDevMode ? [undefined, { debugName: "rowDefInternalDisabled" }] : /* istanbul ignore next */ []));
}
ngOnInit() {
this.vc.createEmbeddedView(this.rowDefInternal().template, {
...this.rowDefInternal()
}, {
injector: Injector.create({
providers: [
{
provide: ROW_DEF_TOKEN,
useValue: this
}
]
})
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableRowDefInternalDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: DatatableRowDefInternalDirective, isStandalone: true, selector: "[rowDefInternal]", inputs: { rowDefInternal: { classPropertyName: "rowDefInternal", publicName: "rowDefInternal", isSignal: true, isRequired: true, transformFunction: null }, rowDefInternalDisabled: { classPropertyName: "rowDefInternalDisabled", publicName: "rowDefInternalDisabled", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DatatableRowDefInternalDirective, decorators: [{
type: Directive,
args: [{
selector: '[rowDefInternal]'
}]
}], propDecorators: { rowDefInternal: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowDefInternal", required: true }] }], rowDefInternalDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowDefInternalDisabled", required: false }] }] } });
const ROW_DEF_TOKEN = new InjectionToken('RowDef');
class DataTableColumnCellDirective {
constructor() {
this.template = inject(TemplateRef);
}
static ngTemplateContextGuard(dir, ctx) {
return true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnCellDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: DataTableColumnCellDirective, isStandalone: true, selector: "[ngx-datatable-cell-template]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnCellDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngx-datatable-cell-template]'
}]
}] });
class DataTableColumnGhostCellDirective {
static ngTemplateContextGuard(directive, context) {
return true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnGhostCellDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: DataTableColumnGhostCellDirective, isStandalone: true, selector: "[ngx-datatable-ghost-cell-template]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnGhostCellDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngx-datatable-ghost-cell-template]'
}]
}] });
class DataTableColumnHeaderDirective {
static ngTemplateContextGuard(directive, context) {
return true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnHeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: DataTableColumnHeaderDirective, isStandalone: true, selector: "[ngx-datatable-header-template]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnHeaderDirective, decorators: [{
type: Directive,
args: [{
selector: '[ngx-datatable-header-template]'
}]
}] });
class DataTableColumnCellTreeToggle {
constructor() {
this.template = inject(TemplateRef);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnCellTreeToggle, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: DataTableColumnCellTreeToggle, isStandalone: true, selector: "[ngx-datatable-tree-toggle]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnCellTreeToggle, decorators: [{
type: Directive,
args: [{
selector: '[ngx-datatable-tree-toggle]'
}]
}] });
class DataTableColumnDirective {
constructor() {
this.name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
this.prop = input(...(ngDevMode ? [undefined, { debugName: "prop" }] : /* istanbul ignore next */ []));
this.bindAsUnsafeHtml = input(false, { ...(ngDevMode ? { debugName: "bindAsUnsafeHtml" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.frozenLeft = input(false, { ...(ngDevMode ? { debugName: "frozenLeft" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.frozenRight = input(false, { ...(ngDevMode ? { debugName: "frozenRight" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.flexGrow = input(undefined, { ...(ngDevMode ? { debugName: "flexGrow" } : /* istanbul ignore next */ {}), transform: numberAttribute });
this.resizeable = input(undefined, { ...(ngDevMode ? { debugName: "resizeable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.comparator = input(...(ngDevMode ? [undefined, { debugName: "comparator" }] : /* istanbul ignore next */ []));
this.pipe = input(...(ngDevMode ? [undefined, { debugName: "pipe" }] : /* istanbul ignore next */ []));
this.sortable = input(undefined, { ...(ngDevMode ? { debugName: "sortable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.draggable = input(undefined, { ...(ngDevMode ? { debugName: "draggable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.canAutoResize = input(undefined, { ...(ngDevMode ? { debugName: "canAutoResize" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.minWidth = input(undefined, { ...(ngDevMode ? { debugName: "minWidth" } : /* istanbul ignore next */ {}), transform: numberAttribute });
this.width = input(undefined, { ...(ngDevMode ? { debugName: "width" } : /* istanbul ignore next */ {}), transform: numberAttribute });
this.maxWidth = input(undefined, { ...(ngDevMode ? { debugName: "maxWidth" } : /* istanbul ignore next */ {}), transform: numberAttribute });
this.checkboxable = input(false, { ...(ngDevMode ? { debugName: "checkboxable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.headerCheckboxable = input(false, { ...(ngDevMode ? { debugName: "headerCheckboxable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.headerClass = input(...(ngDevMode ? [undefined, { debugName: "headerClass" }] : /* istanbul ignore next */ []));
this.cellClass = input(...(ngDevMode ? [undefined, { debugName: "cellClass" }] : /* istanbul ignore next */ []));
this.isTreeColumn = input(false, { ...(ngDevMode ? { debugName: "isTreeColumn" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
this.treeLevelIndent = input(...(ngDevMode ? [undefined, { debugName: "treeLevelIndent" }] : /* istanbul ignore next */ []));
this.summaryFunc = input(...(ngDevMode ? [undefined, { debugName: "summaryFunc" }] : /* istanbul ignore next */ []));
this.summaryTemplate = input(...(ngDevMode ? [undefined, { debugName: "summaryTemplate" }] : /* istanbul ignore next */ []));
this.cellTemplateInput = input(undefined, { ...(ngDevMode ? { debugName: "cellTemplateInput" } : /* istanbul ignore next */ {}), alias: 'cellTemplate' });
this.cellTemplateQuery = contentChild(DataTableColumnCellDirective, { ...(ngDevMode ? { debugName: "cellTemplateQuery" } : /* istanbul ignore next */ {}), read: TemplateRef });
this.headerTemplateInput = input(undefined, { ...(ngDevMode ? { debugName: "headerTemplateInput" } : /* istanbul ignore next */ {}), alias: 'headerTemplate' });
this.headerTemplateQuery = contentChild(DataTableColumnHeaderDirective, { ...(ngDevMode ? { debugName: "headerTemplateQuery" } : /* istanbul ignore next */ {}), read: TemplateRef });
this.treeToggleTemplateInput = input(undefined, { ...(ngDevMode ? { debugName: "treeToggleTemplateInput" } : /* istanbul ignore next */ {}), alias: 'treeToggleTemplate' });
this.treeToggleTemplateQuery = contentChild(DataTableColumnCellTreeToggle, { ...(ngDevMode ? { debugName: "treeToggleTemplateQuery" } : /* istanbul ignore next */ {}), read: TemplateRef });
this.ghostCellTemplateInput = input(undefined, { ...(ngDevMode ? { debugName: "ghostCellTemplateInput" } : /* istanbul ignore next */ {}), alias: 'ghostCellTemplate' });
this.ghostCellTemplateQuery = contentChild(DataTableColumnGhostCellDirective, { ...(ngDevMode ? { debugName: "ghostCellTemplateQuery" } : /* istanbul ignore next */ {}), read: TemplateRef });
/**
* Computed property that returns the column configuration as a TableColumn object
*/
this.column = computed(() => ({
name: this.name(),
prop: this.prop(),
bindAsUnsafeHtml: this.bindAsUnsafeHtml(),
frozenLeft: this.frozenLeft(),
frozenRight: this.frozenRight(),
flexGrow: this.flexGrow(),
resizeable: this.resizeable(),
comparator: this.comparator(),
pipe: this.pipe(),
sortable: this.sortable(),
draggable: this.draggable(),
canAutoResize: this.canAutoResize(),
minWidth: this.minWidth(),
width: this.width(),
maxWidth: this.maxWidth(),
checkboxable: this.checkboxable(),
headerCheckboxable: this.headerCheckboxable(),
headerClass: this.headerClass(),
cellClass: this.cellClass(),
isTreeColumn: this.isTreeColumn(),
treeLevelIndent: this.treeLevelIndent(),
summaryFunc: this.summaryFunc(),
summaryTemplate: this.summaryTemplate(),
cellTemplate: this.cellTemplateInput() ?? this.cellTemplateQuery(),
headerTemplate: this.headerTemplateInput() ?? this.headerTemplateQuery(),
treeToggleTemplate: this.treeToggleTemplateInput() ?? this.treeToggleTemplateQuery(),
ghostCellTemplate: this.ghostCellTemplateInput() ?? this.ghostCellTemplateQuery()
}), ...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.2.9", type: DataTableColumnDirective, isStandalone: true, selector: "ngx-datatable-column", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, prop: { classPropertyName: "prop", publicName: "prop", isSignal: true, isRequired: false, transformFunction: null }, bindAsUnsafeHtml: { classPropertyName: "bindAsUnsafeHtml", publicName: "bindAsUnsafeHtml", isSignal: true, isRequired: false, transformFunction: null }, frozenLeft: { classPropertyName: "frozenLeft", publicName: "frozenLeft", isSignal: true, isRequired: false, transformFunction: null }, frozenRight: { classPropertyName: "frozenRight", publicName: "frozenRight", isSignal: true, isRequired: false, transformFunction: null }, flexGrow: { classPropertyName: "flexGrow", publicName: "flexGrow", isSignal: true, isRequired: false, transformFunction: null }, resizeable: { classPropertyName: "resizeable", publicName: "resizeable", isSignal: true, isRequired: false, transformFunction: null }, comparator: { classPropertyName: "comparator", publicName: "comparator", isSignal: true, isRequired: false, transformFunction: null }, pipe: { classPropertyName: "pipe", publicName: "pipe", isSignal: true, isRequired: false, transformFunction: null }, sortable: { classPropertyName: "sortable", publicName: "sortable", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, canAutoResize: { classPropertyName: "canAutoResize", publicName: "canAutoResize", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, width: { classPropertyName: "width", publicName: "width", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, checkboxable: { classPropertyName: "checkboxable", publicName: "checkboxable", isSignal: true, isRequired: false, transformFunction: null }, headerCheckboxable: { classPropertyName: "headerCheckboxable", publicName: "headerCheckboxable", isSignal: true, isRequired: false, transformFunction: null }, headerClass: { classPropertyName: "headerClass", publicName: "headerClass", isSignal: true, isRequired: false, transformFunction: null }, cellClass: { classPropertyName: "cellClass", publicName: "cellClass", isSignal: true, isRequired: false, transformFunction: null }, isTreeColumn: { classPropertyName: "isTreeColumn", publicName: "isTreeColumn", isSignal: true, isRequired: false, transformFunction: null }, treeLevelIndent: { classPropertyName: "treeLevelIndent", publicName: "treeLevelIndent", isSignal: true, isRequired: false, transformFunction: null }, summaryFunc: { classPropertyName: "summaryFunc", publicName: "summaryFunc", isSignal: true, isRequired: false, transformFunction: null }, summaryTemplate: { classPropertyName: "summaryTemplate", publicName: "summaryTemplate", isSignal: true, isRequired: false, transformFunction: null }, cellTemplateInput: { classPropertyName: "cellTemplateInput", publicName: "cellTemplate", isSignal: true, isRequired: false, transformFunction: null }, headerTemplateInput: { classPropertyName: "headerTemplateInput", publicName: "headerTemplate", isSignal: true, isRequired: false, transformFunction: null }, treeToggleTemplateInput: { classPropertyName: "treeToggleTemplateInput", publicName: "treeToggleTemplate", isSignal: true, isRequired: false, transformFunction: null }, ghostCellTemplateInput: { classPropertyName: "ghostCellTemplateInput", publicName: "ghostCellTemplate", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "cellTemplateQuery", first: true, predicate: DataTableColumnCellDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "headerTemplateQuery", first: true, predicate: DataTableColumnHeaderDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "treeToggleTemplateQuery", first: true, predicate: DataTableColumnCellTreeToggle, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "ghostCellTemplateQuery", first: true, predicate: DataTableColumnGhostCellDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: DataTableColumnDirective, decorators: [{
type: Directive,
args: [{
selector: 'ngx-datatable-column'
}]
}], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], prop: [{ type: i0.Input, args: [{ isSignal: true, alias: "prop", required: false }] }], bindAsUnsafeHtml: [{ type: i0.Input, args: [{ isSignal: true, alias: "bindAsUnsafeHtml", required: false }] }], frozenLeft: [{ type: i0.Input, args: [{ isSignal: true, alias: "frozenLeft", required: false }] }], frozenRight: [{ type: i0.Input, args: [{ isSignal: true, alias: "frozenRight", required: false }] }], flexGrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexGrow", required: false }] }], resizeable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizeable", required: false }] }], comparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "comparator", required: false }] }], pipe: [{ type: i0.Input, args: [{ isSignal: true, alias: "pipe", required: false }] }], sortable: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortable", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], canAutoResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canAutoResize", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], maxWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxWidth", required: false }] }], checkboxable: [{ type: i0.Input, args: [{ isSignal: true, alias: "checkboxable", required: false }] }], headerCheckboxable: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerCheckboxable", required: false }] }], headerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerClass", required: false }] }], cellClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellClass", required: false }] }], isTreeColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "isTreeColumn", required: false }] }], treeLevelIndent: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeLevelIndent", required: false }] }], summaryFunc: [{ type: i0.Input, args: [{ isSignal: true, alias: "summaryFunc", required: false }] }], summaryTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "summaryTemplate", required: false }] }], cellTemplateInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellTemplate", required: false }] }], cellTemplateQuery: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DataTableColumnCellDirective), { ...{ read: TemplateRef }, isSignal: true }] }], headerTemplateInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerTemplate", required: false }] }], headerTemplateQuery: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DataTableColumnHeaderDirective), { ...{
read: TemplateRef
}, isSignal: true }] }], treeToggleTemplateInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "treeToggleTemplate", required: false }] }], treeToggleTemplateQuery: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DataTableColumnCellTreeToggle), { ...{
read: TemplateRef
}, isSignal: true }] }], ghostCellTemplateInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "ghostCellTemplate", required: false }] }], ghostCellTemplateQuery: [{ type: i0.ContentChild, args: [i0.forwardRef(() => DataTableColumnGhostCellDirective), { ...{
read: TemplateRef
}, isSignal: true }] }] } });
/**
* Visibility Observer Directive
*
* Usage:
*
* <div
* visibilityObserver
* (visible)="onVisible($event)">
* </div>
*
*/
class VisibilityDirective {
constructor() {
this.element = inject(ElementRef);
this.zone = inject(NgZone);
this.isVisible = signal(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : /* istanbul ignore next */ []));
this.visible = output();
}
ngOnInit() {
this.runCheck();
}
ngOnDestroy() {
clearTimeout(this.timeout);
}
onVisibilityChange() {
// trigger zone recalc for columns
this.zone.run(() => {
this.isVisible.set(true);
this.visible.emit(true);
});
}
runCheck() {
const check = () => {
// https://davidwalsh.name/offsetheight-visibility
const { offsetHeight, offsetWidth } = this.element.nativeElement;
if (offsetHeight && offsetWidth) {
clearTimeout(this.timeout);
this.onVisibilityChange();
}
else {
clearTimeout(this.timeout);
this.zone.runOutsideAngular(() => {
this.timeout = window.setTimeout(() => check(), 50);
});
}
};
this.timeout = window.setTimeout(() => check());
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: VisibilityDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.9", type: VisibilityDirective, isStandalone: true, selector: "[visibilityObserver]", outputs: { visible: "visible" }, host: { properties: { "class.visible": "isVisible()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: VisibilityDirective, decorators: [{
type: Directive,
args: [{
selector: '[visibilityObserver]',
host: {
'[class.visible]': 'isVisible()'
}
}]
}], propDecorators: { visible: [{ type: i0.Output, args: ["visible"] }] } });
const NGX_DATATABLE_CONFIG = new InjectionToken('ngx-datatable.config');
/**
* Provides a global configuration for ngx-datatable.
*
* @param overrides The overrides of the table configuration.
*/
const providedNgxDatatableConfig = (overrides) => {
return {
provide: NGX_DATATABLE_CONFIG,
useValue: overrides
};
};
/**
* Gets the width of the scrollbar. Nesc for windows
* http://stackoverflow.com/a/13382873/888165
*/
class ScrollbarHelper {
constructor() {
this.document = inject(DOCUMENT);
this.width = this.getWidth();
}
getWidth() {
const outer = this.document.createElement('div');
outer.style.visibility = 'hidden';
outer.style.width = '100px';
this.document.body.appendChild(outer);
const widthNoScroll = outer.offsetWidth;
outer.style.overflow = 'scroll';
const inner = this.document.createElement('div');
inner.style.width = '100%';
outer.appendChild(inner);
const widthWithScroll = inner.offsetWidth;
this.document.body.removeChild(outer);
return widthNoScroll - widthWithScroll;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ScrollbarHelper, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ScrollbarHelper, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ScrollbarHelper, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
/**
* Converts strings from something to camel case
* http://stackoverflow.com/questions/10425287/convert-dash-separated-string-to-camelcase
*/
const camelCase = (str) => {
// Replace special characters with a space
str = str.replace(/[^a-zA-Z0-9 ]/g, ' ');
// put a space before an uppercase letter
str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');
// Lower case first character and some other stuff
str = str
.replace(/([^a-zA-Z0-9 ])|^[0-9]+/g, '')
.trim()
.toLowerCase();
// uppercase characters preceded by a space or number
str = str.replace(/([ 0-9]+)([a-zA-Z])/g, (a, b, c) => {
return b.trim() + c.toUpperCase();
});
return str;
};
/**
* Converts strings from camel case to words
* http://stackoverflow.com/questions/7225407/convert-camelcasetext-to-camel-case-text
*/
const deCamelCase = (str) => {
return str.replace(/([A-Z])/g, match => ` ${match}`).replace(/^./, match => match.toUpperCase());
};
/**
* Always returns the empty string ''
*/
const emptyStringGetter = () => {
return '';
};
/**
* Returns the appropriate getter function for this kind of prop.
* If prop == null, returns the emptyStringGetter.
*/
const getterForProp = (prop) => {
// TODO requires better typing which will also involve adjust TableColum. So postponing it.
if (prop == null) {
return emptyStringGetter;
}
if (typeof prop === 'number') {
return numericIndexGetter;
}
else {
// deep or simple
if (prop.includes('.')) {
return deepValueGetter;
}
else {
return shallowValueGetter;
}
}
};
/**
* Returns the value at this numeric index.
* @param row array of values
* @param index numeric index
* @returns any or '' if invalid index
*/
const numericIndexGetter = (row, index) => {
if (row == null) {
return '';
}
// mimic behavior of deepValueGetter
if (!row || index == null) {
return row;
}
const value = row[index];
if (value == null) {
return '';
}
return value;
};
/**
* Returns the value of a field.
* (more efficient than deepValueGetter)
* @param obj object containing the field
* @param fieldName field name string
*/
const shallowValueGetter = (obj, fieldName) => {
if (obj == null) {
return '';
}
if (!obj || !fieldName) {
return obj;
}
const value = obj[fieldName];
if (value == null) {
return '';
}
return value;
};
/**
* Returns a deep object given a string. zoo['animal.type']
*/
const deepValueGetter = (obj, path) => {
if (obj == null) {
return '';
}
if (!obj || !path) {
return obj;
}
// check if path matches a root-level field
// { "a.b.c": 123 }
let current = obj[path];
if (current !== undefined) {
return current;
}
current = obj;
const split = path.split('.');
if (split.length) {
for (let i = 0; i < split.length; i++) {
current = current[split[i]];
// if found undefined, return empty string
if (current === undefined || current === null) {
return '';
}
}
}
return current;
};
/**
* Creates a unique object id.
* http://stackoverflow.com/questions/6248666/how-to-generate-short-uid-like-ax4j9z-in-js
*/
const id = () => {
return ('0000' + ((Math.random() * Math.pow(36, 4)) << 0).toString(36)).slice(-4);
};
/**
* Gets the next sort direction
*/
const nextSortDir = (sortType, current) => {
if (sortType === 'single') {
if (current === 'asc') {
return 'desc';
}
else {
return 'asc';
}
}
else {
if (!current) {
return 'asc';
}
else if (current === 'asc') {
return 'desc';
}
else if (current === 'desc') {
return undefined;
}
// avoid TS7030: Not all code paths return a value.
return undefined;
}
};
/**
* Adapted from fueld-ui on 6/216
* https://github.com/FuelInteractive/fuel-ui/tree/master/src/pipes/OrderBy
*/
const orderByComparator = (a, b) => {
if (a === null || typeof a === 'undefined') {
a = 0;
}
if (b === null || typeof b === 'undefined') {
b = 0;
}
if (a instanceof Date && b instanceof Date) {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
}
else if (isNaN(parseFloat(a)) || !isFinite(a) || isNaN(parseFloat(b)) || !isFinite(b)) {
// Convert to string in case of a=0 or b=0
a = String(a);
b = String(b);
// Isn't a number so lowercase the string to properly compare
if (a.toLowerCase() < b.toLowerCase()) {
return -1;
}
if (a.toLowerCase() > b.toLowerCase()) {
return 1;
}
}
else {
// Parse strings as numbers to compare properly
if (parseFloat(a) < parseFloat(b)) {
return -1;
}
if (parseFloat(a) > parseFloat(b)) {
return 1;
}
}
// equal each other
return 0;
};
/**
* creates a shallow copy of the `rows` input and returns the sorted copy. this function
* does not sort the `rows` argument in place
*/
const sortRows = (rows, columns, dirs, sortOnGroupHeader) => {
if (!rows) {
return [];
}
if (!dirs?.length || !columns) {
return [...rows];
}
const temp = [...rows];
const cols = columns.reduce((obj, col) => {
if (col.sortable) {
obj[col.prop] = col.comparator;
}
return obj;
}, {});
// cache valueGetter and compareFn so that they
// do not need to be looked-up in the sort function body
const cachedDirs = dirs.map(dir => {
// When sorting on group header, override prop to 'key'
const prop = sortOnGroupHeader?.prop === dir.prop ? 'key' : dir.prop;
// SortDirs may contain columns that are not sortable, so compareFn would be undefined. In that case just return a comparator that returns 0.
const compareFn = cols[dir.prop] ?? (() => 0);
return {
prop,
dir: dir.dir,
valueGetter: getterForProp(prop),
compareFn
};
});
return temp.sort((rowA, rowB) => {
for (const cachedDir of cachedDirs) {
// Get property and valuegetters for column to be sorted
const { prop, valueGetter } = cachedDir;
// Get A and B cell values from rows based on properties of the columns
const propA = valueGetter(rowA, prop);
const propB = valueGetter(rowB, prop);
// Compare function gets five parameters:
// Two cell values to be compared as propA and propB
// Two rows corresponding to the cells as rowA and rowB
// Direction of the sort for this column as SortDirection
// Compare can be a standard JS comparison function (a,b) => -1|0|1
// as additional parameters are silently ignored. The whole row and sort
// direction enable more complex sort logic.
const comparison = cachedDir.dir !== 'desc'
? cachedDir.compareFn(propA, propB, rowA, rowB)
: -cachedDir.compareFn(propA, propB, rowA, rowB);
// Don't return 0 yet in case of needing to sort by next property
if (comparison !== 0) {
return comparison;
}
}
return 0;
});
};
const sortGroupedRows = (groupedRows, columns, dirs, sortOnGroupHeader) => {
if (sortOnGroupHeader) {
groupedRows = sortRows(groupedRows, columns, dirs, sortOnGroupHeader);
}
return groupedRows.map(group => ({ ...group, value: sortRows(group.value, columns, dirs) }));
};
const toInternalColumn = (columns, defaultColumnWidth = 150) => {
let hasTreeColumn = false;
// TS fails to infer the type here.
return columns.map(column => {
const prop = column.prop ?? (column.name ? camelCase(column.name) : undefined);
// Only one column should hold the tree view,
// Thus if multiple columns are provided with
// isTreeColumn as true, we take only the first one
const isTreeColumn = !!column.isTreeColumn && !hasTreeColumn;
hasTreeColumn = hasTreeColumn || isTreeColumn;
// TODO: add check if prop or name is provided if sorting is enabled.
return {
...column,
$$id: id(),
$$originalColumn: column,
$$valueGetter: getterForProp(prop),
prop,
name: column.name ?? (prop ? deCamelCase(String(prop)) : ''),
resizeable: column.resizeable ?? true,
sortable: column.sortable ?? true,
comparator: column.comparator ?? orderByComparator,
draggable: column.draggable ?? true,
canAutoResize: column.canAutoResize ?? true,
width: signal(column.width ?? defaultColumnWidth),
isTreeColumn,
// in case of the directive, those are getters, so call them explicitly.
headerTemplate: column.headerTemplate,
cellTemplate: column.cellTemplate,
summaryTemplate: column.summaryTemplate,
ghostCellTemplate: column.ghostCellTemplate,
treeToggleTemplate: column.treeToggleTemplate
}; // TS cannot cast here
});
};
const toPublicColumn = (column) => {
return {
...column.$$originalColumn,
checkboxable: column.checkboxable,
frozenLeft: column.frozenLeft,
frozenRight: column.frozenRight,
flexGrow: column.flexGrow,
minWidth: column.minWidth,
maxWidth: column.maxWidth,
width: column.width(),
resizeable: column.resizeable,
comparator: column.comparator,
pipe: column.pipe,
sortable: column.sortable,
draggable: column.draggable,
canAutoResize: column.canAutoResize,
name: column.name,
prop: column.prop,
bindAsUnsafeHtml: column.bindAsUnsafeHtml,
cellTemplate: column.cellTemplate,
ghostCellTemplate: column.ghostCellTemplate,
headerTemplate: column.headerTemplate,
treeToggleTemplate: column.treeToggleTemplate,
cellClass: column.cellClass,
headerClass: column.headerClass,
headerCheckboxable: column.headerCheckboxable,
isTreeColumn: column.isTreeColumn,
treeLevelIndent: column.treeLevelIndent,
summaryFunc: column.summaryFunc,
summaryTemplate: column.summaryTemplate
};
};
/**
* Returns the columns by pin.
*/
const columnsByPin = (cols) => {
const ret = {
left: [],
center: [],
right: []
};
if (cols) {
for (const col of cols) {
if (col.frozenLeft) {
ret.left.push(col);
}
else if (col.frozenRight) {
ret.right.push(col);
}
else {
ret.center.push(col);
}
}
}
return ret;
};
/**
* Returns the widths of all group sets of a column
*/
const columnGroupWidths = (groups, all) => {
return {
left: columnTotalWidth(groups.left),
center: columnTotalWidth(groups.center),
right: columnTotalWidth(groups.right),
total: Math.floor(columnTotalWidth(all))
};
};
/**
* Calculates the total width of all columns
*/
const columnTotalWidth = (columns) => {
return columns?.reduce((total, column) => total + column.width(), 0) ?? 0;
};
const columnsByPinArr = (val) => {
const colsByPin = columnsByPin(val);
return [
{ type: 'left', columns: colsByPin.left },
{ type: 'center', columns: colsByPin.center },
{ type: 'right', columns: colsByPin.right }
];
};
/**
* Calculates the Total Flex Grow
*/
const getTotalFlexGrow = (columns) => {
let totalFlexGrow = 0;
for (const c of columns) {
totalFlexGrow += c.flexGrow ?? 0;
}
return totalFlexGrow;
};
/**
* Adjusts the column widths.
* Inspired by: https://github.com/facebook/fixed-data-table/blob/master/src/FixedDataTableWidthHelper.js
*/
const adjustColumnWidths = (allColumns, expectedWidth) => {
const columnsWidth = columnTotalWidth(allColumns);
const totalFlexGrow = getTotalFlexGrow(allColumns);
const colsByGroup = columnsByPin(allColumns);
if (columnsWidth !== expectedWidth) {
scaleColumns(colsByGroup, expectedWidth, totalFlexGrow);
}
};
/**
* Resizes columns based on the flexGrow property, while respecting manually set widths
*/
const scaleColumns = (colsByGroup, maxWidth, totalFlexGrow) => {
const columns = Object.values(colsByGroup).flat();
let remainingWidth = maxWidth;
// calculate total width and flexgrow points for columns that can be resized
for (const column of columns) {
if (column.$$oldWidth) {
// when manually resized, switch off auto-resize
column.canAutoResize = false;
}
if (!column.canAutoResize) {
remainingWidth -= column.width();
totalFlexGrow -= column.flexGrow ?? 0;
}
else {
column.width.set(0);
}
}
const hasMinWidth = {};
// resize columns until no width is left to be distributed
do {
const widthPerFlexPoint = remainingWidth / totalFlexGrow;
remainingWidth = 0;
for (const column of columns) {
// if the column can be resize and it hasn't reached its minimum width yet
if (column.canAutoResize && !hasMinWidth[column.prop]) {
const newWidth = column.width() + (column.flexGrow ?? 0) * widthPerFlexPoint;
if (column.minWidth !== undefined && newWidth < column.minWidth) {
remainingWidth += newWidth - column.minWidth;
column.width.set(column.minWidth);
hasMinWidth[column.prop] = true;
}
else {
column.width.set(newWidth);
}
}
}
} while (remainingWidth !== 0);
// Adjust for any remaining offset in computed widths vs maxWidth
const totalWidthAchieved = columns.reduce((acc, col) => acc + col.width(), 0);
const delta = maxWidth - totalWidthAchieved;
if (delta === 0) {
return;
}
// adjust the first column that can be auto-resized respecting the min/max widths
for (const col of columns.filter(c => c.canAutoResize).sort((a, b) => a.width() - b.width())) {
if ((delta > 0 && (!col.maxWidth || col.width() + delta <= col.maxWidth)) ||
(delta < 0 && (!col.minWidth || col.width() + delta >= col.minWidth))) {
col.width.update(value => value + delta);
break;
}
}
};
/**
* Forces the width of the columns to
* distribute equally but overflowing when necessary
*
* Rules:
*
* - If combined withs are less than the total width of the grid,
* proportion the widths given the min / max / normal widths to fill the width.
*
* - If the combined widths, exceed the total width of the grid,
* use the standard widths.
*
* - If a column is resized, it should always use that width
*
* - The proportional widths should never fall below min size if specified.
*
* - If the grid starts off small but then becomes greater than the size ( + / - )
* the width should use the original width; not the newly proportioned widths.
*/
const forceFillColumnWidths = (allColumns, expectedWidth, startIdx, allowBleed, defaultColWidth = 150, verticalScrollWidth = 0) => {
const columnsToResize = allColumns
.slice(startIdx + 1, allColumns.length)
.filter(c => c.canAutoResize !== false);
for (const column of columnsToResize) {
if (!column.$$oldWidth) {
column.$$oldWidth = column.width();
}
}
let additionWidthPerColumn = 0;
let exceedsWindow = false;
let contentWidth = getContentWidth(allColumns, defaultColWidth);
let remainingWidth = expectedWidth - contentWidth;
const initialRemainingWidth = remainingWidth;
const columnsProcessed = [];
const remainingWidthLimit = 1; // when to stop
// This loop takes care of the
do {
additionWidthPerColumn = remainingWidth / columnsToResize.length;
exceedsWindow = contentWidth >= expectedWidth;
for (const column of columnsToResize) {
// don't bleed if the initialRemainingWidth is same as verticalScrollWidth
if (exceedsWindow && allowBleed && initialRemainingWidth !== -1 * verticalScrollWidth) {
column.width.update(value => value || defaultColWidth);
}
else {
const newSize = (column.width() || defaultColWidth) + additionWidthPerColumn;
if (column.minWidth && newSize < column.minWidth) {
column.width.set(column.minWidth);
columnsProcessed.push(column);
}
else if (column.maxWidth && newSize > column.maxWidth) {
column.width.set(column.maxWidth);
columnsProcessed.push(column);
}
else {
column.width.set(newSize);
}
}
column.width.update(value => Math.max(0, value));
}
contentWidth = getContentWidth(allColumns, defaultColWidth);
remainingWidth = expectedWidth - contentWidth;
removeProcessedColumns(columnsToResize, columnsProcessed);
} while (remainingWidth > remainingWidthLimit && columnsToResize.length !== 0);
// reset so we don't have stale values
for (const column of columnsToResize) {
column.$$oldWidth = 0;
}
}