UNPKG

imng-prime-table-odata

Version:

This library was generated with [Nx](https://nx.dev).

439 lines (427 loc) 20 kB
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