imng-prime-table-odata
Version:
This library was generated with [Nx](https://nx.dev).
439 lines (427 loc) • 20 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, Inject, Component, inject, ChangeDetectorRef, Input, Directive, ChangeDetectionStrategy, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Table, TableModule } from 'primeng/table';
import { Subscriptions } from 'imng-ngrx-utils';
import * as i2 from 'rxjs';
import { isObservable, map, distinct, tap } from 'rxjs';
import * as i1 from '@angular/router';
import { isCompositeFilter, getFilterOperator } from 'imng-odata-client';
import { getRelatedValue, toLocalTimeStamp, isRelatedFieldOptions, getRelatedField } from 'imng-nrsrx-client-utils';
import { EnumProperties, getEnumDisplayText } from 'openapi-ts-generator/enums';
/* eslint-disable @angular-eslint/prefer-inject */
const FACADE = new InjectionToken('imng-prime-table-odata-facade');
const STATE = new InjectionToken('imng-prime-table-state');
class ImngPrimeODataTableBaseComponent {
constructor(facade, state, router = null, //NOSONAR
tableRefresh$ = null) {
this.facade = facade;
this.state = state;
this.router = router;
this.tableRefresh$ = tableRefresh$;
this.allSubscriptions = new Subscriptions();
this.ENUM_DISPLAY_TEXT = EnumProperties.DISPLAY_TEXT;
this.ENUM_NAME = EnumProperties.NAME;
this.getEnumDisplayText = getEnumDisplayText;
/**
* This sets the amount of the maximum amount of sortable columns for this component. Default = 5.
*/
this.maxSortedColumnCount = 5; //NOSONAR
this.tableStateQueryKey = 'tableState';
this.rowsPerPageOptions = [10, 20, 50, 100];
this.getRelatedValue = getRelatedValue;
this.excelData = () => this.tableData$;
if (this.router?.routerState?.snapshot?.root.queryParams[this.tableStateQueryKey]) {
try {
this.tableState = this.deserializeTableState(this.router?.routerState?.snapshot?.root?.queryParams[this.tableStateQueryKey]);
}
catch (e) {
console.error(
//NOSONAR
`Exception thrown while deserializing query string parameter: ${this.tableStateQueryKey}.`, e);
}
}
if (isObservable(state)) {
this.allSubscriptions.push(state.subscribe((t) => {
this.tableState = t;
this.expanders = t.expand;
this.appliedTransformations = t.apply;
}));
}
else {
this.tableState = this.tableState
? {
...this.tableState,
select: state.select,
expand: state.expand,
}
: state;
this.expanders = state.expand;
this.appliedTransformations = state.apply;
}
if (tableRefresh$) {
this.allSubscriptions.push(tableRefresh$.subscribe(() => this.loadEntities(this.tableState)));
}
}
ngOnInit() {
if (!this.tableRefresh$) {
this.loadEntities(this.tableState);
}
this.activeEffectCount$ = this.facade.activeEffectCount$;
this.tableData$ = this.facade.tableData$?.pipe(map((table) => table ?? []));
this.allSubscriptions.push(this.facade.tableState$
.pipe(distinct(), tap((t) => {
if (this.router) {
this.updateRouterState(t);
}
}))
.subscribe());
}
ngOnDestroy() {
this.allSubscriptions.unsubscribeAll();
}
getExportFileName(exportName) {
return `${exportName}-${toLocalTimeStamp()}`;
}
/**
* Naming convention:
* . => Parent table navigation separator
* / => Child table navigation separator
* @param segments
* @returns
*/
getRelatedField(...segments) {
if (!segments.length) {
return null;
}
const initialSegment = segments[0];
if (isRelatedFieldOptions(initialSegment)) {
return getRelatedField(initialSegment);
}
return getRelatedField({ segments: segments.map((m) => m.toString()) });
}
deserializeTableState(stateQueryParam) {
return JSON.parse(atob(stateQueryParam));
}
/**
* This method ensures the proper handling of date filters in an OData query
* @param filter
*/
normalizeFilters(filter) {
if (isCompositeFilter(filter)) {
filter.filters.forEach(this.normalizeFilters);
}
else if (filter?.field?.toUpperCase() === 'DATE' ||
filter?.field?.toUpperCase().endsWith('DATE') ||
filter?.field?.toUpperCase().endsWith('UTC')) {
filter.value = new Date(filter.value);
}
}
serializeTableState(primeTableState) {
return btoa(JSON.stringify(primeTableState));
}
/**
* Will reset filters to initialGrid state passed into the constructor
*/
resetFilters() {
if (!isObservable(this.state)) {
this.tableState = {
...this.state,
filters: this.state.filters,
};
this.loadEntities(this.tableState);
}
}
dataStateChange(primeTableState) {
this.tableState = {
...primeTableState,
expand: this.expanders,
apply: this.appliedTransformations,
};
this.loadEntities(this.tableState);
}
loadEntities(primeTableState) {
this.tableState = {
...primeTableState,
multiSortMeta: this.validateSortParameters(primeTableState.multiSortMeta),
};
this.expanders = primeTableState.expand;
this.appliedTransformations = primeTableState.apply;
this.facade.loadEntities(this.tableState);
}
validateSortParameters(multiSortMeta) {
if (multiSortMeta?.length &&
multiSortMeta?.length > this.maxSortedColumnCount) {
multiSortMeta = multiSortMeta.slice(0, this.maxSortedColumnCount);
console.warn(`You have exceeded the limit of ${this.maxSortedColumnCount} sorted columns for the current table. MAX-Sorted-Column-Count`); //NOSONAR
}
return multiSortMeta || [];
}
updateRouterState(state) {
if (this.router) {
const tempState = { ...state };
delete tempState.select;
delete tempState.expand;
this.router.navigate([], {
relativeTo: this.router.routerState.root,
queryParams: {
[this.tableStateQueryKey]: this.serializeTableState(tempState),
},
skipLocationChange: false,
queryParamsHandling: 'merge',
});
}
}
reloadEntities() {
this.facade.reloadEntities();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ImngPrimeODataTableBaseComponent, deps: [{ token: FACADE }, { token: STATE }, { token: i1.Router }, { token: i2.Observable }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: ImngPrimeODataTableBaseComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: '', isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ImngPrimeODataTableBaseComponent, decorators: [{
type: Component,
args: [{
template: '',
}]
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [FACADE]
}] }, { type: undefined, decorators: [{
type: Inject,
args: [STATE]
}] }, { type: i1.Router }, { type: i2.Observable }] });
function handleMultiColumnSorting(val, sortState) {
//The following code is due to a bug in the MultiSortMeta
//This object is currently only returning the latest user defined sort
if (val.multiSortMeta?.filter((t) => t).length) {
const sort = val.multiSortMeta[0];
const matchingSort = sortState.find((f) => sort.field === f.field);
sortState = sortState.filter((f) => sort.field !== f.field);
if (matchingSort?.order !== -1) {
sortState.push(sort);
}
}
return sortState;
}
class IMNG_PRIME_TABLE {
constructor() {
this.tableComponent = inject(Table);
this.changeDetectorRef = inject(ChangeDetectorRef);
this.sortState = [];
this.allSubscriptions = new Subscriptions();
}
ngOnInit() {
this.facade = this.odataTableComponent.facade || {};
this.tableComponent.responsiveLayout = 'scroll';
this.tableComponent.paginator = true;
this.tableComponent.lazy = true;
this.tableComponent.styleClass = 'p-datatable-gridlines';
this.tableComponent.sortMode = 'multiple';
this.tableComponent.showCurrentPageReport = true;
this.tableComponent.rowHover = true;
this.tableComponent.resizableColumns = true;
this.tableComponent.reorderableColumns = true;
this.tableComponent.currentPageReportTemplate =
'Showing {first} to {last} of {totalRecords} entries';
this.tableComponent.rowsPerPageOptions =
this.odataTableComponent.rowsPerPageOptions;
this.allSubscriptions.push(this.facade.tableData$.subscribe((t) => {
this.tableComponent.value = t || [];
this.changeDetectorRef.markForCheck();
}));
this.allSubscriptions.push(this.facade.activeEffectCount$.subscribe((t) => {
this.tableComponent.loading = t > 0;
this.changeDetectorRef.markForCheck();
}));
this.allSubscriptions.push(this.facade.totalRecordCount$.subscribe((t) => {
this.tableComponent.totalRecords = t || 0;
this.changeDetectorRef.markForCheck();
}));
this.allSubscriptions.push(this.facade.tableState$.subscribe((newTableState) => {
this.tableComponent.rows = newTableState?.rows || 20;
if (newTableState.first &&
this.tableComponent.first !== newTableState.first) {
this.tableComponent.first = newTableState.first;
}
if (newTableState.filters) {
const newFilters = {};
Object.keys(newTableState.filters)
.filter((newFilterKey) => newTableState.filters?.[newFilterKey])
.forEach((newFilterKey) => {
newFilters[newFilterKey] = [
...(newTableState.filters?.[newFilterKey]?.map((filterMetadata) => ({
...filterMetadata,
})) || []),
];
});
this.tableComponent.filters = newFilters;
}
this.tableComponent.multiSortMeta =
newTableState.multiSortMeta?.map((sort) => ({
...sort,
})) || [];
this.changeDetectorRef.markForCheck();
}));
this.allSubscriptions.push(this.tableComponent.onLazyLoad.subscribe((x) => {
this.tableComponent.multiSortMeta =
this.sortState =
x.multiSortMeta =
this.odataTableComponent.validateSortParameters(handleMultiColumnSorting(x, this.sortState));
if (x.globalFilter && x.filters?.['global']) {
const globalFilter = x.filters['global'];
this.tableComponent.globalFilterFields?.forEach((field) => {
const filterVal = x.filters?.[field];
if (filterVal.length === 1) {
filterVal[0].value = globalFilter.value;
filterVal[0].matchMode = globalFilter.matchMode;
filterVal[0].operator = 'or';
}
});
delete x.filters['global'];
}
this.facade.loadEntities(x);
}));
}
ngOnDestroy() {
this.allSubscriptions.unsubscribeAll();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: IMNG_PRIME_TABLE, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.10", type: IMNG_PRIME_TABLE, isStandalone: true, selector: "[imngODataTable]", inputs: { odataTableComponent: ["imngODataTable", "odataTableComponent"] }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: IMNG_PRIME_TABLE, decorators: [{
type: Directive,
args: [{
selector: '[imngODataTable]',
}]
}], propDecorators: { odataTableComponent: [{
type: Input,
args: ['imngODataTable']
}] } });
class IMNG_PRIME_SEARCH_CAPTION {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: IMNG_PRIME_SEARCH_CAPTION, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.10", type: IMNG_PRIME_SEARCH_CAPTION, isStandalone: true, selector: "imng-prime-search-caption", inputs: { dataTable: "dataTable" }, ngImport: i0, template: "<div class=\"d-flex flex-row-reverse\">\n <button\n pButton\n label=\"Clear\"\n class=\"btn btn-outline-secondary ms-2\"\n (click)=\"dataTable.clear()\">\n <em class=\"pi pi-filter-slash\"></em>\n Clear\n </button>\n <div class=\"input-group w-25\">\n <input\n type=\"text\"\n class=\"form-control\"\n #globalFilter\n pInputText\n (keyup)=\"dataTable.filterGlobal(globalFilter.value, 'contains')\"\n placeholder=\"Search keyword\" />\n <button pButton label=\"Clear\" class=\"btn btn-outline-secondary\">\n <em class=\"pi pi-search\"></em>\n Search\n </button>\n </div>\n</div>\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: IMNG_PRIME_SEARCH_CAPTION, decorators: [{
type: Component,
args: [{ selector: 'imng-prime-search-caption', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"d-flex flex-row-reverse\">\n <button\n pButton\n label=\"Clear\"\n class=\"btn btn-outline-secondary ms-2\"\n (click)=\"dataTable.clear()\">\n <em class=\"pi pi-filter-slash\"></em>\n Clear\n </button>\n <div class=\"input-group w-25\">\n <input\n type=\"text\"\n class=\"form-control\"\n #globalFilter\n pInputText\n (keyup)=\"dataTable.filterGlobal(globalFilter.value, 'contains')\"\n placeholder=\"Search keyword\" />\n <button pButton label=\"Clear\" class=\"btn btn-outline-secondary\">\n <em class=\"pi pi-search\"></em>\n Search\n </button>\n </div>\n</div>\n" }]
}], propDecorators: { dataTable: [{
type: Input
}] } });
class ImngPrimeTableODataModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ImngPrimeTableODataModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.10", ngImport: i0, type: ImngPrimeTableODataModule, imports: [CommonModule,
TableModule,
IMNG_PRIME_TABLE,
IMNG_PRIME_SEARCH_CAPTION], exports: [IMNG_PRIME_TABLE, IMNG_PRIME_SEARCH_CAPTION] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ImngPrimeTableODataModule, imports: [CommonModule,
TableModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.10", ngImport: i0, type: ImngPrimeTableODataModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule,
TableModule,
IMNG_PRIME_TABLE,
IMNG_PRIME_SEARCH_CAPTION,
],
exports: [IMNG_PRIME_TABLE, IMNG_PRIME_SEARCH_CAPTION],
}]
}] });
function toODataQuery(val) {
const query = {
...val,
orderBy: val.multiSortMeta?.map((x) => ({
field: x.field,
dir: x.order === -1 ? 'desc' : 'asc',
})),
skip: val.first,
top: val.rows,
};
if (val.filters) {
const filters = Object.keys(val.filters || {})
.filter((key) => val.filters?.[key]?.some((e) => e.value))
.map((key) => ({
key,
collection: val.filters?.[key] || [],
}))
.filter((metaData) => metaData.collection?.filter((filter) => filter.value).length)
.map((t) => ({
logic: t.collection?.every((e) => e.operator === 'and')
? 'and'
: 'or',
filters: t.collection.map((m) => ({
field: t.key,
operator: getFilterOperator(m.matchMode || 'eq'),
value: m.value,
})),
}));
if (filters?.length) {
query.filter = {
logic: filters.some((e) => e.logic === 'or') ? 'or' : 'and',
filters,
};
}
}
delete query.filters;
delete query.multiSortMeta;
if (query.filter) {
query.filter = transformPrimeRelatedTableFilters(query.filter);
}
return query;
}
function transformPrimeRelatedTableFilters(filter) {
if (filter) {
filter.filters = filter.filters.map((x) => {
if (isCompositeFilter(x)) {
return transformPrimeRelatedTableFilters(x);
}
else if (x.field.indexOf('/') > 0) {
const fieldSegments = x.field.split('/');
return {
...x,
childTable: fieldSegments[0].replaceAll('.', '/'),
field: fieldSegments.filter((v, i) => i > 0).join('/'),
linqOperation: 'any',
};
}
else if (x.field.indexOf('.') > 0) {
x.field = x.field.replaceAll('.', '/');
}
return x;
});
}
return filter;
}
function createPrimeODataTableInitialState() {
return {
tableData: [],
totalRecordCount: 0,
activeEffectCount: 0,
tableState: {},
error: undefined,
};
}
function incrementActiveEffectCount(state) {
return {
...state,
activeEffectCount: state.activeEffectCount + 1,
};
}
function decrementActiveEffectCount(state) {
return {
...state,
activeEffectCount: state.activeEffectCount - 1 < 0 ? 0 : state.activeEffectCount - 1,
};
}
function imngPrimeEffectErrorReducer(state, effectError) {
return {
...decrementActiveEffectCount(state),
error: effectError.payload.error,
};
}
/**
* Generated bundle index. Do not edit.
*/
export { IMNG_PRIME_SEARCH_CAPTION, IMNG_PRIME_TABLE, ImngPrimeODataTableBaseComponent, ImngPrimeTableODataModule, createPrimeODataTableInitialState, decrementActiveEffectCount, handleMultiColumnSorting, imngPrimeEffectErrorReducer, incrementActiveEffectCount, toODataQuery, transformPrimeRelatedTableFilters };
//# sourceMappingURL=imng-prime-table-odata.mjs.map