UNPKG

@bhplugin/ng-datatable

Version:

ng-datatable - fully customizable & easy to use datatable library

877 lines (858 loc) 118 kB
import * as i0 from '@angular/core'; import { Directive, Input, EventEmitter, Component, Output, ViewChild, ViewEncapsulation, ChangeDetectionStrategy, ContentChildren, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i2 from '@angular/forms'; import { FormsModule } from '@angular/forms'; import * as i1$1 from '@angular/platform-browser'; class colDef { } class Pager { } class SlotDirective { constructor(templateRef) { this.templateRef = templateRef; } } SlotDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SlotDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); SlotDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: SlotDirective, selector: "[slot]", inputs: { fieldName: ["slot", "fieldName"], value: ["slotValue", "value"] }, ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: SlotDirective, decorators: [{ type: Directive, args: [{ selector: '[slot]', }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }]; }, propDecorators: { fieldName: [{ type: Input, args: ['slot'] }], value: [{ type: Input, args: ['slotValue'] }] } }); class ColumnFilterComponent { constructor() { this.close = new EventEmitter(); this.filterChange = new EventEmitter(); } ngOnInit() { document.addEventListener('click', this.closeMethod.bind(this)); } ngOnDestroy() { document.removeEventListener('click', this.closeMethod.bind(this)); } closeMethod() { this.close.emit(); } select(condition) { this.column.condition = condition; if (condition === '') { this.column.value = ''; } this.filterChange.emit(this.column); } } ColumnFilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ColumnFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); ColumnFilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: ColumnFilterComponent, selector: "column-filter", inputs: { column: "column" }, outputs: { close: "close", filterChange: "filterChange" }, ngImport: i0, template: ` <div class="bh-filter-menu bh-absolute bh-z-[1] bh-bg-white bh-shadow-md bh-rounded-md bh-top-full bh-right-0 bh-w-32 bh-mt-1"> <div class="bh-text-[13px] bh-font-normal bh-rounded bh-overflow-hidden" (click)="closeMethod(); $event.stopPropagation()"> <button type="button" [class.active]="column.condition === ''" (click)="select('')">No filter</button> <ng-container *ngIf="column.type === 'string'"> <button type="button" [class.active]="column.condition === 'contain'" (click)="select('contain')">Contain</button> <button type="button" [class.active]="column.condition === 'not_contain'" (click)="select('not_contain')">Not contain</button> <button type="button" [class.active]="column.condition === 'equal'" (click)="select('equal')">Equal</button> <button type="button" [class.active]="column.condition === 'not_equal'" (click)="select('not_equal')">Not equal</button> <button type="button" [class.active]="column.condition === 'start_with'" (click)="select('start_with')">Starts with</button> <button type="button" [class.active]="column.condition === 'end_with'" (click)="select('end_with')">Ends with</button> </ng-container> <ng-container *ngIf="column.type === 'number'"> <button type="button" [class.active]="column.condition === 'equal'" (click)="select('equal')">Equal</button> <button type="button" [class.active]="column.condition === 'not_equal'" (click)="select('not_equal')">Not Equal</button> <button type="button" [class.active]="column.condition === 'greater_than'" (click)="select('greater_than')">Greater than</button> <button type="button" [class.active]="column.condition === 'greater_than_equal'" (click)="select('greater_than_equal')">Greater than or equal</button> <button type="button" [class.active]="column.condition === 'less_than'" (click)="select('less_than')">Less than</button> <button type="button" [class.active]="column.condition === 'less_than_equal'" (click)="select('less_than_equal')">Less than or equal</button> </ng-container> <ng-container *ngIf="column.type === 'date'"> <button type="button" [ngClass]="{ active: column.condition === 'equal' }" (click)="select('equal')">Equal</button> <button type="button" [ngClass]="{ active: column.condition === 'not_equal' }" (click)="select('not_equal')">Not equal</button> <button type="button" [ngClass]="{ active: column.condition === 'greater_than' }" (click)="select('greater_than')">Greater than</button> <button type="button" [ngClass]="{ active: column.condition === 'less_than' }" (click)="select('less_than')">Less than</button> </ng-container> <button type="button" [ngClass]="{ active: column.condition === 'is_null' }" (click)="select('is_null')">Is null</button> <button type="button" [ngClass]="{ active: column.condition === 'is_not_null' }" (click)="select('is_not_null')">Not null</button> </div> </div> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ColumnFilterComponent, decorators: [{ type: Component, args: [{ selector: 'column-filter', template: ` <div class="bh-filter-menu bh-absolute bh-z-[1] bh-bg-white bh-shadow-md bh-rounded-md bh-top-full bh-right-0 bh-w-32 bh-mt-1"> <div class="bh-text-[13px] bh-font-normal bh-rounded bh-overflow-hidden" (click)="closeMethod(); $event.stopPropagation()"> <button type="button" [class.active]="column.condition === ''" (click)="select('')">No filter</button> <ng-container *ngIf="column.type === 'string'"> <button type="button" [class.active]="column.condition === 'contain'" (click)="select('contain')">Contain</button> <button type="button" [class.active]="column.condition === 'not_contain'" (click)="select('not_contain')">Not contain</button> <button type="button" [class.active]="column.condition === 'equal'" (click)="select('equal')">Equal</button> <button type="button" [class.active]="column.condition === 'not_equal'" (click)="select('not_equal')">Not equal</button> <button type="button" [class.active]="column.condition === 'start_with'" (click)="select('start_with')">Starts with</button> <button type="button" [class.active]="column.condition === 'end_with'" (click)="select('end_with')">Ends with</button> </ng-container> <ng-container *ngIf="column.type === 'number'"> <button type="button" [class.active]="column.condition === 'equal'" (click)="select('equal')">Equal</button> <button type="button" [class.active]="column.condition === 'not_equal'" (click)="select('not_equal')">Not Equal</button> <button type="button" [class.active]="column.condition === 'greater_than'" (click)="select('greater_than')">Greater than</button> <button type="button" [class.active]="column.condition === 'greater_than_equal'" (click)="select('greater_than_equal')">Greater than or equal</button> <button type="button" [class.active]="column.condition === 'less_than'" (click)="select('less_than')">Less than</button> <button type="button" [class.active]="column.condition === 'less_than_equal'" (click)="select('less_than_equal')">Less than or equal</button> </ng-container> <ng-container *ngIf="column.type === 'date'"> <button type="button" [ngClass]="{ active: column.condition === 'equal' }" (click)="select('equal')">Equal</button> <button type="button" [ngClass]="{ active: column.condition === 'not_equal' }" (click)="select('not_equal')">Not equal</button> <button type="button" [ngClass]="{ active: column.condition === 'greater_than' }" (click)="select('greater_than')">Greater than</button> <button type="button" [ngClass]="{ active: column.condition === 'less_than' }" (click)="select('less_than')">Less than</button> </ng-container> <button type="button" [ngClass]="{ active: column.condition === 'is_null' }" (click)="select('is_null')">Is null</button> <button type="button" [ngClass]="{ active: column.condition === 'is_not_null' }" (click)="select('is_not_null')">Not null</button> </div> </div> `, }] }], ctorParameters: function () { return []; }, propDecorators: { column: [{ type: Input }], close: [{ type: Output, args: ['close'] }], filterChange: [{ type: Output, args: ['filterChange'] }] } }); class IconCheckComponent { constructor(viewContainerRef) { this.viewContainerRef = viewContainerRef; } ngOnInit() { this.viewContainerRef.createEmbeddedView(this.template); } } IconCheckComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: IconCheckComponent, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); IconCheckComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: IconCheckComponent, selector: "icon-check", inputs: { class: "class" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["template"], descendants: true, static: true }], ngImport: i0, template: ` <ng-template #template> <svg [ngClass]="class" version="1.1" viewBox="0 0 17 12"> <g fill="none" fill-rule="evenodd"> <g transform="translate(-9 -11)" fill="currentColor" fill-rule="nonzero"> <path d="m25.576 11.414c0.56558 0.55188 0.56558 1.4439 0 1.9961l-9.404 9.176c-0.28213 0.27529-0.65247 0.41385-1.0228 0.41385-0.37034 0-0.74068-0.13855-1.0228-0.41385l-4.7019-4.588c-0.56584-0.55188-0.56584-1.4442 0-1.9961 0.56558-0.55214 1.4798-0.55214 2.0456 0l3.679 3.5899 8.3812-8.1779c0.56558-0.55214 1.4798-0.55214 2.0456 0z" /> </g> </g> </svg> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: IconCheckComponent, decorators: [{ type: Component, args: [{ selector: 'icon-check', template: ` <ng-template #template> <svg [ngClass]="class" version="1.1" viewBox="0 0 17 12"> <g fill="none" fill-rule="evenodd"> <g transform="translate(-9 -11)" fill="currentColor" fill-rule="nonzero"> <path d="m25.576 11.414c0.56558 0.55188 0.56558 1.4439 0 1.9961l-9.404 9.176c-0.28213 0.27529-0.65247 0.41385-1.0228 0.41385-0.37034 0-0.74068-0.13855-1.0228-0.41385l-4.7019-4.588c-0.56584-0.55188-0.56584-1.4442 0-1.9961 0.56558-0.55214 1.4798-0.55214 2.0456 0l3.679 3.5899 8.3812-8.1779c0.56558-0.55214 1.4798-0.55214 2.0456 0z" /> </g> </g> </svg> </ng-template> `, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; }, propDecorators: { template: [{ type: ViewChild, args: ['template', { static: true }] }], class: [{ type: Input }] } }); class IconDashComponent { constructor(viewContainerRef) { this.viewContainerRef = viewContainerRef; } ngOnInit() { this.viewContainerRef.createEmbeddedView(this.template); } } IconDashComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: IconDashComponent, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); IconDashComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: IconDashComponent, selector: "icon-dash", inputs: { class: "class" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["template"], descendants: true, static: true }], ngImport: i0, template: ` <ng-template #template> <svg [ngClass]="class" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"> <line x1="5" y1="12" x2="19" y2="12"></line> </svg> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: IconDashComponent, decorators: [{ type: Component, args: [{ selector: 'icon-dash', template: ` <ng-template #template> <svg [ngClass]="class" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round"> <line x1="5" y1="12" x2="19" y2="12"></line> </svg> </ng-template> `, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; }, propDecorators: { template: [{ type: ViewChild, args: ['template', { static: true }] }], class: [{ type: Input }] } }); class IconFilterComponent { constructor(viewContainerRef) { this.viewContainerRef = viewContainerRef; } ngOnInit() { this.viewContainerRef.createEmbeddedView(this.template); } } IconFilterComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: IconFilterComponent, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); IconFilterComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: IconFilterComponent, selector: "icon-filter", inputs: { class: "class" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["template"], descendants: true, static: true }], ngImport: i0, template: ` <ng-template #template> <svg [ngClass]="class" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"> <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon> </svg> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: IconFilterComponent, decorators: [{ type: Component, args: [{ selector: 'icon-filter', template: ` <ng-template #template> <svg [ngClass]="class" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round"> <polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"></polygon> </svg> </ng-template> `, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; }, propDecorators: { template: [{ type: ViewChild, args: ['template', { static: true }] }], class: [{ type: Input }] } }); class ColumnHeaderComponent { constructor(viewContainerRef) { this.viewContainerRef = viewContainerRef; this.selectAll = new EventEmitter(); this.sortChange = new EventEmitter(); this.filterChange = new EventEmitter(); this.isOpenFilter = null; } ngOnInit() { this.viewContainerRef.createEmbeddedView(this.template); this.checkboxChange(); } checkboxChange() { if (this.selectedAll) { this.selectedAll.nativeElement.indeterminate = this.checkAll !== 0 ? !this.checkAll : false; this.selectedAll.nativeElement.checked = this.checkAll; } } toggleFilterMenu(col) { if (col) { if (this.isOpenFilter === col.field) { this.isOpenFilter = null; } else { this.isOpenFilter = col.field; } } else { this.isOpenFilter = null; } } } ColumnHeaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ColumnHeaderComponent, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); ColumnHeaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: ColumnHeaderComponent, selector: "column-header", inputs: { all: "all", isFooter: "isFooter", checkAll: "checkAll" }, outputs: { selectAll: "selectAll", sortChange: "sortChange", filterChange: "filterChange" }, viewQueries: [{ propertyName: "template", first: true, predicate: ["template"], descendants: true, static: true }, { propertyName: "selectedAll", first: true, predicate: ["selectedAll"], descendants: true }], ngImport: i0, template: ` <ng-template #template> <tr> <th *ngIf="all.hasCheckbox" [class]="'bh-w-px'" [ngClass]="{ 'bh-sticky bh-bg-blue-light bh-z-[1]': all.stickyHeader || all.stickyFirstColumn, 'bh-top-0': all.stickyHeader, 'bh-left-0': all.stickyFirstColumn }" > <div class="bh-checkbox"> <input #selectedAll type="checkbox" (click)="selectAll.emit(selectedAll.checked); $event.stopPropagation()" /> <div> <icon-check class="check"></icon-check> <icon-dash class="intermediate"></icon-dash> </div> </div> </th> <ng-container *ngFor="let col of all.columns; let j = index"> <th *ngIf="!col.hide" [class]="'bh-select-none bh-z-[1]'" [ngClass]="[ all.sortable && col.sort ? 'bh-cursor-pointer' : '', j === 0 && all.stickyFirstColumn ? 'bh-sticky bh-left-0 bh-bg-blue-light' : '', all.hasCheckbox && j === 0 && all.stickyFirstColumn ? 'bh-left-[52px]' : '' ]" [style]="{ width: col.width, 'min-width': col.minWidth, 'max-width': col.maxWidth }" > <div class="bh-flex bh-items-center" [ngClass]="[col.headerClass ? col.headerClass : '']" (click)="all.sortable && col.sort && sortChange.emit(col.field)"> {{ col.title }} <span *ngIf="all.sortable && col.sort" class="bh-ml-3 bh-sort bh-flex bh-items-center" [ngClass]="[all.sortColumn, all.sortDirection]"> <svg width="16" height="16" viewBox="0 0 14 14" fill="none"> <polygon points="3.11,6.25 10.89,6.25 7,1.75" fill="currentColor" class="bh-text-black/20" [ngClass]="[all.sortColumn === col.field && all.sortDirection === 'asc' ? '!bh-text-primary' : '']" ></polygon> <polygon points="7,12.25 10.89,7.75 3.11,7.75" fill="currentColor" class="bh-text-black/20" [ngClass]="[all.sortColumn === col.field && all.sortDirection === 'desc' ? '!bh-text-primary' : '']" ></polygon> </svg> </span> </div> <ng-container *ngIf="all.columnFilter && !isFooter"> <div *ngIf="col.filter" class="bh-filter bh-relative"> <input *ngIf="col.type === 'string'" [(ngModel)]="col.value" type="text" class="bh-form-control" (keyup)="filterChange.emit()" /> <input *ngIf="col.type === 'number'" [(ngModel)]="col.value" type="number" class="bh-form-control" (keyup)="filterChange.emit()" /> <input *ngIf="col.type === 'date'" [(ngModel)]="col.value" type="date" class="bh-form-control" (change)="filterChange.emit()" /> <select *ngIf="col.type === 'bool'" [(ngModel)]="col.value" class="bh-form-control" (change)="filterChange.emit()" (click)="isOpenFilter = null"> <option [ngValue]="undefined">All</option> <option [ngValue]="true">True</option> <option [ngValue]="false">False</option> </select> <button *ngIf="col.type !== 'bool'" type="button" (click)="toggleFilterMenu(col); $event.stopPropagation()"> <icon-filter class="bh-w-4"></icon-filter> </button> <column-filter [ngClass]="{ 'bh-hidden': isOpenFilter !== col.field }" [column]="col" (close)="toggleFilterMenu()" (filterChange)="filterChange.emit()" ></column-filter> </div> </ng-container> </th> </ng-container> </tr> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["column"], outputs: ["close", "filterChange"] }, { kind: "component", type: IconCheckComponent, selector: "icon-check", inputs: ["class"] }, { kind: "component", type: IconDashComponent, selector: "icon-dash", inputs: ["class"] }, { kind: "component", type: IconFilterComponent, selector: "icon-filter", inputs: ["class"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ColumnHeaderComponent, decorators: [{ type: Component, args: [{ selector: 'column-header', template: ` <ng-template #template> <tr> <th *ngIf="all.hasCheckbox" [class]="'bh-w-px'" [ngClass]="{ 'bh-sticky bh-bg-blue-light bh-z-[1]': all.stickyHeader || all.stickyFirstColumn, 'bh-top-0': all.stickyHeader, 'bh-left-0': all.stickyFirstColumn }" > <div class="bh-checkbox"> <input #selectedAll type="checkbox" (click)="selectAll.emit(selectedAll.checked); $event.stopPropagation()" /> <div> <icon-check class="check"></icon-check> <icon-dash class="intermediate"></icon-dash> </div> </div> </th> <ng-container *ngFor="let col of all.columns; let j = index"> <th *ngIf="!col.hide" [class]="'bh-select-none bh-z-[1]'" [ngClass]="[ all.sortable && col.sort ? 'bh-cursor-pointer' : '', j === 0 && all.stickyFirstColumn ? 'bh-sticky bh-left-0 bh-bg-blue-light' : '', all.hasCheckbox && j === 0 && all.stickyFirstColumn ? 'bh-left-[52px]' : '' ]" [style]="{ width: col.width, 'min-width': col.minWidth, 'max-width': col.maxWidth }" > <div class="bh-flex bh-items-center" [ngClass]="[col.headerClass ? col.headerClass : '']" (click)="all.sortable && col.sort && sortChange.emit(col.field)"> {{ col.title }} <span *ngIf="all.sortable && col.sort" class="bh-ml-3 bh-sort bh-flex bh-items-center" [ngClass]="[all.sortColumn, all.sortDirection]"> <svg width="16" height="16" viewBox="0 0 14 14" fill="none"> <polygon points="3.11,6.25 10.89,6.25 7,1.75" fill="currentColor" class="bh-text-black/20" [ngClass]="[all.sortColumn === col.field && all.sortDirection === 'asc' ? '!bh-text-primary' : '']" ></polygon> <polygon points="7,12.25 10.89,7.75 3.11,7.75" fill="currentColor" class="bh-text-black/20" [ngClass]="[all.sortColumn === col.field && all.sortDirection === 'desc' ? '!bh-text-primary' : '']" ></polygon> </svg> </span> </div> <ng-container *ngIf="all.columnFilter && !isFooter"> <div *ngIf="col.filter" class="bh-filter bh-relative"> <input *ngIf="col.type === 'string'" [(ngModel)]="col.value" type="text" class="bh-form-control" (keyup)="filterChange.emit()" /> <input *ngIf="col.type === 'number'" [(ngModel)]="col.value" type="number" class="bh-form-control" (keyup)="filterChange.emit()" /> <input *ngIf="col.type === 'date'" [(ngModel)]="col.value" type="date" class="bh-form-control" (change)="filterChange.emit()" /> <select *ngIf="col.type === 'bool'" [(ngModel)]="col.value" class="bh-form-control" (change)="filterChange.emit()" (click)="isOpenFilter = null"> <option [ngValue]="undefined">All</option> <option [ngValue]="true">True</option> <option [ngValue]="false">False</option> </select> <button *ngIf="col.type !== 'bool'" type="button" (click)="toggleFilterMenu(col); $event.stopPropagation()"> <icon-filter class="bh-w-4"></icon-filter> </button> <column-filter [ngClass]="{ 'bh-hidden': isOpenFilter !== col.field }" [column]="col" (close)="toggleFilterMenu()" (filterChange)="filterChange.emit()" ></column-filter> </div> </ng-container> </th> </ng-container> </tr> </ng-template> `, }] }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }]; }, propDecorators: { template: [{ type: ViewChild, args: ['template', { static: true }] }], selectedAll: [{ type: ViewChild, args: ['selectedAll'] }], all: [{ type: Input }], isFooter: [{ type: Input }], checkAll: [{ type: Input }], selectAll: [{ type: Output, args: ['selectAll'] }], sortChange: [{ type: Output, args: ['sortChange'] }], filterChange: [{ type: Output, args: ['filterChange'] }] } }); class IconLoaderComponent { constructor() { } } IconLoaderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: IconLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); IconLoaderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.9", type: IconLoaderComponent, selector: "icon-loader", ngImport: i0, template: ` <svg width="84" height="84" viewBox="0 0 24 24" class="bh-loader bh-text-primary"> <circle cx="18" cy="12" r="0" fill="currentColor"> <animate attributeName="r" begin=".67" calcMode="spline" dur="1.5s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0" /> </circle> <circle cx="12" cy="12" r="0" fill="currentColor"> <animate attributeName="r" begin=".33" calcMode="spline" dur="1.5s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0" /> </circle> <circle cx="6" cy="12" r="0" fill="currentColor"> <animate attributeName="r" begin="0" calcMode="spline" dur="1.5s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0" /> </circle> </svg> `, isInline: true }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: IconLoaderComponent, decorators: [{ type: Component, args: [{ selector: 'icon-loader', template: ` <svg width="84" height="84" viewBox="0 0 24 24" class="bh-loader bh-text-primary"> <circle cx="18" cy="12" r="0" fill="currentColor"> <animate attributeName="r" begin=".67" calcMode="spline" dur="1.5s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0" /> </circle> <circle cx="12" cy="12" r="0" fill="currentColor"> <animate attributeName="r" begin=".33" calcMode="spline" dur="1.5s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0" /> </circle> <circle cx="6" cy="12" r="0" fill="currentColor"> <animate attributeName="r" begin="0" calcMode="spline" dur="1.5s" keySplines="0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8;0.2 0.2 0.4 0.8" repeatCount="indefinite" values="0;2;0;0" /> </circle> </svg> `, }] }], ctorParameters: function () { return []; } }); class NgDataTableComponent { constructor(sanitizer) { this.sanitizer = sanitizer; // props this.loading = false; this.isServerMode = false; this.skin = 'bh-table-striped bh-table-hover'; this.totalRows = 0; this.rows = []; this.columns = []; this.hasCheckbox = false; this.search = ''; this.page = 1; this.pageSize = 10; this.pageSizeOptions = [10, 20, 30, 50, 100]; this.showPageSize = true; this.rowClass = ''; this.cellClass = ''; this.sortable = false; this.sortColumn = 'id'; this.sortDirection = 'asc'; this.columnFilter = false; this.pagination = true; this.showNumbers = true; this.showNumbersCount = 5; this.showFirstPage = true; this.showLastPage = true; this.firstArrow = ''; this.lastArrow = ''; this.nextArrow = ''; this.previousArrow = ''; this.paginationInfo = 'Showing {0} to {1} of {2} entries'; this.noDataContent = 'No data available'; this.stickyHeader = false; this.height = '500px'; this.stickyFirstColumn = false; this.cloneHeaderInFooter = false; this.selectRowOnClick = false; this.showFooterRow = false; // events this.changeServer = new EventEmitter(); this.sortChange = new EventEmitter(); this.searchChange = new EventEmitter(); this.pageChange = new EventEmitter(); this.pageSizeChange = new EventEmitter(); this.rowSelect = new EventEmitter(); this.filterChange = new EventEmitter(); this.rowClick = new EventEmitter(); this.rowDBClick = new EventEmitter(); // variables this.filterItems = []; this.currentPage = this.page; this.currentPageSize = this.pagination ? this.pageSize : this.rows.length; this.oldPageSize = this.pageSize; this.currentSortColumn = this.sortColumn; this.oldSortColumn = this.sortColumn; this.currentSortDirection = this.sortDirection; this.oldSortDirection = this.sortDirection; this.filterRowCount = this.totalRows; this.selectedAll = null; this.currentLoader = this.loading; this.currentSearch = this.search; this.uniqueKey = ''; this.pager = new Pager(); //row click this.timer = null; this.delay = 230; this.slotsMap = new Map(); } ngOnInit() { this.initDeafultValues(); this.changeRows(); } ngOnChanges(changes) { // watch loading if (changes['loading'] && !changes['loading'].firstChange) { this.currentLoader = this.loading; } // watch rows and columns if ((changes['rows'] && !changes['rows'].firstChange) || (changes['columns'] && !changes['columns'].firstChange)) { if (!this.isServerMode) { this.currentPage = 1; this.oldColumns = this.noReact(this.columns); } this.changeRows(); } // watch page if (!this.isServerMode) { if (changes['page'] && !changes['page'].firstChange) { this.movePage(this.page); } } // watch pagesize if (changes['pageSize'] && !changes['pageSize'].firstChange) { this.currentPageSize = this.pagination ? this.pageSize : this.rows.length; if (!this.isServerMode) { this.changePageSize(); } } // watch search if (changes['search'] && !changes['search'].firstChange) { this.currentSearch = this.search; this.changeSearch(); } // watch sort column and direction if (!this.isServerMode) { if ((changes['sortColumn'] && !changes['sortColumn'].firstChange) || (changes['sortDirection'] && !changes['sortDirection'].firstChange)) { this.sortChangeMethod(this.sortColumn, this.sortDirection); } } } initDeafultValues() { this.currentLoader = this.loading; this.currentSearch = this.search; this.currentSortColumn = this.sortColumn; this.currentSortDirection = this.sortDirection; this.filterRowCount = this.totalRows; this.currentPage = this.page; if (this.pagination) { const exists = this.pageSizeOptions.find((d) => d === this.pageSize); this.currentPageSize = exists ? this.pageSize : 10; } else { this.currentPageSize = this.rows.length; } this.oldPageSize = this.pageSize; this.oldSortColumn = this.sortColumn; this.oldSortDirection = this.sortDirection; // set default columns values for (const item of this.columns || []) { const type = item.type?.toLowerCase() || 'string'; item.type = type; item.isUnique = item.isUnique !== undefined ? item.isUnique : false; item.hide = item.hide !== undefined ? item.hide : false; item.filter = item.filter !== undefined ? item.filter : true; item.search = item.search !== undefined ? item.search : true; item.sort = item.sort !== undefined ? item.sort : true; item.html = item.html !== undefined ? item.html : false; item.condition = !type || type === 'string' ? 'contain' : 'equal'; } this.oldColumns = this.noReact(this.columns); this.setUniqueKey(); } get getProps() { return { loading: this.currentLoader, isServerMode: this.isServerMode, skin: this.skin, totalRows: this.filterRowCount, rows: this.rows, columns: this.columns, hasCheckbox: this.hasCheckbox, search: this.currentSearch, page: this.currentPage, pageSize: this.currentPageSize, pageSizeOptions: this.pageSizeOptions, showPageSize: this.showPageSize, rowClass: this.rowClass, cellClass: this.cellClass, sortable: this.sortable, sortColumn: this.currentSortColumn, sortDirection: this.currentSortDirection, columnFilter: this.columnFilter, pagination: this.pagination, showNumbers: this.showNumbers, showNumbersCount: this.showNumbersCount, showFirstPage: this.showFirstPage, showLastPage: this.showLastPage, firstArrow: this.firstArrow, lastArrow: this.lastArrow, nextArrow: this.nextArrow, previousArrow: this.previousArrow, paginationInfo: this.paginationInfo, noDataContent: this.noDataContent, stickyHeader: this.stickyHeader, height: this.height, stickyFirstColumn: this.stickyFirstColumn, cloneHeaderInFooter: this.cloneHeaderInFooter, selectRowOnClick: this.selectRowOnClick, showFooterRow: this.showFooterRow, }; } isFunction(value) { return typeof value === 'function'; } stringFormat() { const args = [this.filterRowCount ? this.offset() : 0, this.limit(), this.filterRowCount]; return this.paginationInfo.replace(/{(\d+)}/g, (match, number) => { return typeof args[number] != 'undefined' ? args[number] : match; }); } setUniqueKey() { const col = this.columns.find((d) => d.isUnique); this.uniqueKey = col?.field || ''; } maxPage() { const totalPages = this.currentPageSize < 1 ? 1 : Math.ceil(this.filterRowCount / this.currentPageSize); return Math.max(totalPages || 0, 1); } offset() { return (this.currentPage - 1) * this.currentPageSize + 1; } limit() { const limit = this.currentPage * this.currentPageSize; return this.filterRowCount >= limit ? limit : this.filterRowCount; } getPager() { // total pages let totalPages = this.maxPage(); // pages let startPage, endPage; let isMaxSized = typeof this.showNumbersCount !== 'undefined' && this.showNumbersCount < totalPages; // recompute if maxSize if (isMaxSized) { // Current page is displayed in the middle of the visible ones startPage = Math.max(this.currentPage - Math.floor(this.showNumbersCount / 2), 1); endPage = startPage + this.showNumbersCount - 1; // Adjust if limit is exceeded if (endPage > totalPages) { endPage = totalPages; startPage = endPage - this.showNumbersCount + 1; } } else { startPage = 1; endPage = totalPages; } const pages = Array.from(Array(endPage + 1 - startPage).keys()).map((i) => startPage + i); return { totalRows: this.isServerMode ? this.totalRows : this.filterItems.length, currentPage: this.currentPage, pageSize: this.pageSize, maxPage: totalPages, startPage: startPage, endPage: endPage, stringFormat: this.stringFormat(), pages: pages, }; } setPager() { this.pager = this.getPager(); } filterRows() { let result = []; let rows = this.rows || []; if (this.isServerMode) { this.filterRowCount = this.totalRows || 0; result = rows; } else { this.columns?.forEach((d) => { if (d.filter && ((d.value !== undefined && d.value !== null && d.value !== '') || d.condition === 'is_null' || d.condition === 'is_not_null')) { // string filters if (d.type === 'string') { if (d.value && !d.condition) { d.condition = 'contain'; } if (d.condition === 'contain') { rows = rows.filter((item) => { return this.cellValue(item, d.field)?.toString().toLowerCase().includes(d.value.toLowerCase()); }); } else if (d.condition === 'not_contain') { rows = rows.filter((item) => { return !this.cellValue(item, d.field)?.toString().toLowerCase().includes(d.value.toLowerCase()); }); } else if (d.condition === 'equal') { rows = rows.filter((item) => { return this.cellValue(item, d.field)?.toString().toLowerCase() === d.value.toLowerCase(); }); } else if (d.condition === 'not_equal') { rows = rows.filter((item) => { return this.cellValue(item, d.field)?.toString().toLowerCase() !== d.value.toLowerCase(); }); } else if (d.condition === 'start_with') { rows = rows.filter((item) => { return this.cellValue(item, d.field)?.toString().toLowerCase().indexOf(d.value.toLowerCase()) === 0; }); } else if (d.condition === 'end_with') { rows = rows.filter((item) => { return (this.cellValue(item, d.field) ?.toString() .toLowerCase() .substr(d.value.length * -1) === d.value.toLowerCase()); }); } } // number filters else if (d.type === 'number') { if (d.value && !d.condition) { d.condition = 'equal'; } if (d.condition === 'equal') { rows = rows.filter((item) => { return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) === parseFloat(d.value); }); } else if (d.condition === 'not_equal') { rows = rows.filter((item) => { return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) !== parseFloat(d.value); }); } else if (d.condition === 'greater_than') { rows = rows.filter((item) => { return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) > parseFloat(d.value); }); } else if (d.condition === 'greater_than_equal') { rows = rows.filter((item) => { return this.cellValue(item, d.field) && parseFloat(this.cellValue(item, d.field)) >= parseFloat(d.value); }); } else if (d.condition === 'less_than') { rows = rows.filter((item) => { return this.cellValue(item, d.field) && parseFloat(this.cellValue(it