@mediusinc/mng-commons 7.0.0-rc.1 → 7.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/index.d.ts +24 -4
- package/fesm2022/mediusinc-mng-commons-core.mjs +108 -72
- package/fesm2022/mediusinc-mng-commons-core.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-filter.mjs +16 -0
- package/fesm2022/mediusinc-mng-commons-filter.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-form-api.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-form.mjs +406 -49
- package/fesm2022/mediusinc-mng-commons-form.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-model-class.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-model.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-table-api-class.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-table-api.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-table-column-toggle.component-BQ99oqWO.mjs +30 -0
- package/fesm2022/mediusinc-mng-commons-table-column-toggle.component-BQ99oqWO.mjs.map +1 -0
- package/fesm2022/mediusinc-mng-commons-table-mediusinc-mng-commons-table-BLuM5Kpu.mjs +2700 -0
- package/fesm2022/mediusinc-mng-commons-table-mediusinc-mng-commons-table-BLuM5Kpu.mjs.map +1 -0
- package/fesm2022/mediusinc-mng-commons-table.mjs +1 -1
- package/fesm2022/mediusinc-mng-commons-tableview-api-class.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-tableview-api.mjs +31 -3
- package/fesm2022/mediusinc-mng-commons-tableview-api.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons-tableview.mjs +155 -123
- package/fesm2022/mediusinc-mng-commons-tableview.mjs.map +1 -1
- package/fesm2022/mediusinc-mng-commons.mjs.map +1 -1
- package/filter/index.d.ts +13 -0
- package/form/index.d.ts +109 -22
- package/i18n/en.json +12 -1
- package/i18n/sl.json +12 -1
- package/package.json +24 -24
- package/table/api/index.d.ts +2 -2
- package/table/index.d.ts +97 -29
- package/tableview/api/index.d.ts +17 -2
- package/tableview/index.d.ts +7 -1
- package/version-info.json +6 -6
- package/fesm2022/mediusinc-mng-commons-table-column-toggle.component-0Dtv48mq.mjs +0 -30
- package/fesm2022/mediusinc-mng-commons-table-column-toggle.component-0Dtv48mq.mjs.map +0 -1
- package/fesm2022/mediusinc-mng-commons-table-mediusinc-mng-commons-table-BsAwyXiN.mjs +0 -2417
- package/fesm2022/mediusinc-mng-commons-table-mediusinc-mng-commons-table-BsAwyXiN.mjs.map +0 -1
|
@@ -0,0 +1,2700 @@
|
|
|
1
|
+
import { trigger, transition, style, animate } from '@angular/animations';
|
|
2
|
+
import { NgTemplateOutlet, NgClass, DecimalPipe, CurrencyPipe, DatePipe, AsyncPipe } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { Injectable, inject, signal, computed, untracked, ElementRef, Renderer2, ChangeDetectorRef, input, booleanAttribute, viewChild, ChangeDetectionStrategy, ViewEncapsulation, Component, LOCALE_ID, Pipe, output, forwardRef, model, InjectionToken, Directive, contentChildren, HostListener, Injector, DestroyRef, afterNextRender } from '@angular/core';
|
|
5
|
+
import { takeUntilDestroyed, toObservable, toSignal, outputFromObservable } from '@angular/core/rxjs-interop';
|
|
6
|
+
import * as i1 from '@angular/forms';
|
|
7
|
+
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
8
|
+
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
|
|
9
|
+
import { OverlayService, MessageService, PrimeTemplate } from 'primeng/api';
|
|
10
|
+
import { DomHandler, ConnectedOverlayScrollHandler } from 'primeng/dom';
|
|
11
|
+
import { InputGroup } from 'primeng/inputgroup';
|
|
12
|
+
import { InputGroupAddon } from 'primeng/inputgroupaddon';
|
|
13
|
+
import { InputNumber } from 'primeng/inputnumber';
|
|
14
|
+
import { InputText } from 'primeng/inputtext';
|
|
15
|
+
import * as i1$1 from 'primeng/table';
|
|
16
|
+
import { TableModule, Table } from 'primeng/table';
|
|
17
|
+
import { ToggleSwitch } from 'primeng/toggleswitch';
|
|
18
|
+
import { ZIndexUtils } from 'primeng/utils';
|
|
19
|
+
import { Subject, debounceTime, distinctUntilChanged, ReplaySubject, switchMap, NEVER, BehaviorSubject, combineLatest, skip, of, filter } from 'rxjs';
|
|
20
|
+
import { FilterMatchMode, dateToIsoString, angularDateFormatHasTime, angularDateFormatHasSeconds, fromAngularDateFormatToPrime, fromAngularNumberFormatToFractions, effectWithDeps, getI18nTypePropertyKey, RerenderDirective, GetterPipe, TemplatePipe, JsonPathPipe, ComponentDirective, BooleanPipe, EnumPipe, isMac, TemplateDirective, findTemplateByName, getI18nErrorParams, getI18nForError, toastMessage, CommonsService, COMMONS_MODULE_CONFIG_IT, toObservable as toObservable$1, CommonsStorageService, LoggerService, booleanOrUndefinedAttribute, mergeDataListParamsWithDefaults, fromTableLoadToDataListParams, dataListParamsToUrlQuery, fromSubscribeError, getErrorLogLevel, fromUrlQueryToDataListParams, I18nPropertyPipe, ClassMapPipe, CommonsFeatureTypeEnum } from '@mediusinc/mng-commons/core';
|
|
21
|
+
import { FilterTypeEnum, FilterDescriptor, FilterLookupTypeEnum, FilterLookupDescriptor, FilterDisplayTypeEnum } from '@mediusinc/mng-commons/filter';
|
|
22
|
+
import { DateRangeComponent, AutocompleteComponent, DropdownComponent, InputTrimDirective, NumberRangeComponent, AutocompleteTemplateDirective, DropdownTemplateDirective, DateRangeTemplateDirective, NumberRangeTemplateDirective, DatetimePickerComponent } from '@mediusinc/mng-commons/form';
|
|
23
|
+
import { ButtonDirective } from 'primeng/button';
|
|
24
|
+
import { Tooltip } from 'primeng/tooltip';
|
|
25
|
+
import { ColumnDisplayTypeEnum, tableDescriptor, TableDynamicDescriptorInst, TablePaginationModeEnum, TableSizeEnum } from '@mediusinc/mng-commons/table/api';
|
|
26
|
+
import { Divider } from 'primeng/divider';
|
|
27
|
+
import { Menu } from 'primeng/menu';
|
|
28
|
+
import { Tag, TagModule } from 'primeng/tag';
|
|
29
|
+
import { Checkbox } from 'primeng/checkbox';
|
|
30
|
+
import { Message } from 'primeng/message';
|
|
31
|
+
import { ToggleButton } from 'primeng/togglebutton';
|
|
32
|
+
import { lookupDataProvider } from '@mediusinc/mng-commons/form/api';
|
|
33
|
+
import { Chip } from 'primeng/chip';
|
|
34
|
+
import { MultiSelect } from 'primeng/multiselect';
|
|
35
|
+
import { IconField } from 'primeng/iconfield';
|
|
36
|
+
import { InputIcon } from 'primeng/inputicon';
|
|
37
|
+
import { Popover } from 'primeng/popover';
|
|
38
|
+
import { Skeleton } from 'primeng/skeleton';
|
|
39
|
+
import { SplitButton } from 'primeng/splitbutton';
|
|
40
|
+
import { Router, ActivatedRoute, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';
|
|
41
|
+
import { getI18nForModel } from '@mediusinc/mng-commons/model';
|
|
42
|
+
import { PrimeNG } from 'primeng/config';
|
|
43
|
+
|
|
44
|
+
function filterGenerateMatchModeOptions(primeConfig, descriptor, cmpSerCfg) {
|
|
45
|
+
let options = undefined;
|
|
46
|
+
if (descriptor == null || descriptor.filterType === FilterTypeEnum.String) {
|
|
47
|
+
options = [
|
|
48
|
+
{ value: FilterMatchMode.Contains, label: primeConfig.getTranslation(FilterMatchMode.Contains) },
|
|
49
|
+
{ value: FilterMatchMode.NotContains, label: primeConfig.getTranslation(FilterMatchMode.NotContains) },
|
|
50
|
+
{ value: FilterMatchMode.Equals, label: primeConfig.getTranslation(FilterMatchMode.Equals) },
|
|
51
|
+
{ value: FilterMatchMode.NotEquals, label: primeConfig.getTranslation(FilterMatchMode.NotEquals) },
|
|
52
|
+
{ value: FilterMatchMode.In, label: primeConfig.getTranslation(FilterMatchMode.In) },
|
|
53
|
+
{ value: FilterMatchMode.NotIn, label: primeConfig.getTranslation(FilterMatchMode.NotIn) },
|
|
54
|
+
{ value: FilterMatchMode.StartsWith, label: primeConfig.getTranslation(FilterMatchMode.StartsWith) },
|
|
55
|
+
{ value: FilterMatchMode.EndsWith, label: primeConfig.getTranslation(FilterMatchMode.EndsWith) }
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
else if (descriptor.filterType === FilterTypeEnum.Boolean) {
|
|
59
|
+
options = [{ value: FilterMatchMode.Equals, label: primeConfig.getTranslation(FilterMatchMode.Equals) }];
|
|
60
|
+
}
|
|
61
|
+
else if (descriptor.filterType === FilterTypeEnum.Number) {
|
|
62
|
+
options = [
|
|
63
|
+
{ value: FilterMatchMode.Equals, label: primeConfig.getTranslation(FilterMatchMode.Equals) },
|
|
64
|
+
{ value: FilterMatchMode.NotEquals, label: primeConfig.getTranslation(FilterMatchMode.NotEquals) },
|
|
65
|
+
{ value: FilterMatchMode.LessThan, label: primeConfig.getTranslation(FilterMatchMode.LessThan) },
|
|
66
|
+
{ value: FilterMatchMode.LessThanOrEqualTo, label: primeConfig.getTranslation(FilterMatchMode.LessThanOrEqualTo) },
|
|
67
|
+
{ value: FilterMatchMode.GreaterThan, label: primeConfig.getTranslation(FilterMatchMode.GreaterThan) },
|
|
68
|
+
{ value: FilterMatchMode.GreaterThanOrEqualTo, label: primeConfig.getTranslation(FilterMatchMode.GreaterThanOrEqualTo) },
|
|
69
|
+
{ value: FilterMatchMode.Between, label: primeConfig.getTranslation(FilterMatchMode.Between) },
|
|
70
|
+
...(descriptor.displayFormat === undefined
|
|
71
|
+
? [
|
|
72
|
+
{ value: FilterMatchMode.In, label: primeConfig.getTranslation(FilterMatchMode.In) },
|
|
73
|
+
{ value: FilterMatchMode.NotIn, label: primeConfig.getTranslation(FilterMatchMode.NotIn) }
|
|
74
|
+
]
|
|
75
|
+
: [])
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
else if (descriptor.filterType === FilterTypeEnum.Lookup || descriptor.filterType === FilterTypeEnum.LookupEnum) {
|
|
79
|
+
options = [
|
|
80
|
+
{ value: FilterMatchMode.Equals, label: primeConfig.getTranslation(FilterMatchMode.Equals) },
|
|
81
|
+
{ value: FilterMatchMode.NotEquals, label: primeConfig.getTranslation(FilterMatchMode.NotEquals) },
|
|
82
|
+
{ value: FilterMatchMode.In, label: primeConfig.getTranslation(FilterMatchMode.In) },
|
|
83
|
+
{ value: FilterMatchMode.NotIn, label: primeConfig.getTranslation(FilterMatchMode.NotIn) }
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
else if (descriptor.filterType === FilterTypeEnum.Date) {
|
|
87
|
+
if (!descriptor.datePickerShowTime && !descriptor.dateValueNoTime && !cmpSerCfg?.filtersDateOnlyDisabled) {
|
|
88
|
+
options = [
|
|
89
|
+
{ value: FilterMatchMode.Equals, label: primeConfig.getTranslation(FilterMatchMode.Equals) },
|
|
90
|
+
{ value: FilterMatchMode.NotEquals, label: primeConfig.getTranslation(FilterMatchMode.NotEquals) },
|
|
91
|
+
{ value: FilterMatchMode.LessThanOrEqualTo, label: primeConfig.getTranslation(FilterMatchMode.LessThanOrEqualTo) },
|
|
92
|
+
{ value: FilterMatchMode.GreaterThanOrEqualTo, label: primeConfig.getTranslation(FilterMatchMode.GreaterThanOrEqualTo) },
|
|
93
|
+
{ value: FilterMatchMode.Between, label: primeConfig.getTranslation(FilterMatchMode.Between) }
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
options = [
|
|
98
|
+
{ value: FilterMatchMode.Equals, label: primeConfig.getTranslation(FilterMatchMode.Equals) },
|
|
99
|
+
{ value: FilterMatchMode.LessThanOrEqualTo, label: primeConfig.getTranslation(FilterMatchMode.LessThanOrEqualTo) },
|
|
100
|
+
{ value: FilterMatchMode.GreaterThanOrEqualTo, label: primeConfig.getTranslation(FilterMatchMode.GreaterThanOrEqualTo) },
|
|
101
|
+
{ value: FilterMatchMode.Between, label: primeConfig.getTranslation(FilterMatchMode.Between) }
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
options?.push({ value: FilterMatchMode.Exists, label: primeConfig.getTranslation(FilterMatchMode.Exists) }, { value: FilterMatchMode.DoesNotExist, label: primeConfig.getTranslation(FilterMatchMode.DoesNotExist) });
|
|
106
|
+
if (descriptor?.matchModes) {
|
|
107
|
+
options = descriptor.matchModes.map(mm => ({ value: mm, label: primeConfig.getTranslation(mm) }));
|
|
108
|
+
}
|
|
109
|
+
return options || [];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Gets the default match mode for a filter.
|
|
113
|
+
*
|
|
114
|
+
* @param {FilterDescriptor<any, any>} [descriptor] - The filter descriptor.
|
|
115
|
+
* @param {SelectItem[]} [matchModes=[]] - The available match modes options.
|
|
116
|
+
*
|
|
117
|
+
* @return {FilterMatchModeExtendedType} The default match mode for the filter.
|
|
118
|
+
*/
|
|
119
|
+
function filterGetDefaultMatchMode(descriptor, matchModes = []) {
|
|
120
|
+
let defaultMatchMode = FilterMatchMode.Equals;
|
|
121
|
+
if (descriptor?.filterType === FilterTypeEnum.String)
|
|
122
|
+
defaultMatchMode = FilterMatchMode.StartsWith;
|
|
123
|
+
// overwrite type default set in descriptor
|
|
124
|
+
if (descriptor?.defaultMatchMode) {
|
|
125
|
+
defaultMatchMode = descriptor.defaultMatchMode;
|
|
126
|
+
}
|
|
127
|
+
// check if default mode exists!
|
|
128
|
+
if (matchModes.length > 0 && !matchModes.some(m => m.value === defaultMatchMode)) {
|
|
129
|
+
defaultMatchMode = matchModes[0].value;
|
|
130
|
+
}
|
|
131
|
+
return defaultMatchMode;
|
|
132
|
+
}
|
|
133
|
+
function filterSetStateOnChange(filter, matchMode, value, filterType, filterDateCfg) {
|
|
134
|
+
let displayValue = filter?.displayValue ?? value;
|
|
135
|
+
let displayMatchMode = filter?.displayMatchMode ?? matchMode;
|
|
136
|
+
// when equals is used on dates with time, the actual filter will be between, but displayed as equals
|
|
137
|
+
if (filterType === FilterTypeEnum.Date && !filterDateCfg?.valueNoTime) {
|
|
138
|
+
if (matchMode === FilterMatchMode.Between &&
|
|
139
|
+
Array.isArray(value) &&
|
|
140
|
+
value.length === 2 &&
|
|
141
|
+
value.every(v => v instanceof Date || typeof v === 'string' || typeof v === 'number')) {
|
|
142
|
+
if (filterAreDatesEqual(value[0], value[1], filterDateCfg)) {
|
|
143
|
+
displayMatchMode = FilterMatchMode.Equals;
|
|
144
|
+
displayValue = new Date(value[0]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else if (matchMode === FilterMatchMode.Equals && !value) {
|
|
148
|
+
matchMode = FilterMatchMode.Between;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (filterType === FilterTypeEnum.Date && displayValue) {
|
|
152
|
+
// display value for calendar cannot be string, convert to date
|
|
153
|
+
displayValue = Array.isArray(displayValue)
|
|
154
|
+
? displayValue.map(v => (!(v instanceof Date) ? new Date(v) : v))
|
|
155
|
+
: displayValue instanceof Date
|
|
156
|
+
? displayValue
|
|
157
|
+
: new Date(displayValue);
|
|
158
|
+
}
|
|
159
|
+
if (filterType === FilterTypeEnum.Boolean && displayValue != null && typeof displayValue !== 'boolean') {
|
|
160
|
+
displayValue = (typeof displayValue === 'string' && displayValue.toLowerCase() === 'true') || displayValue === 1;
|
|
161
|
+
}
|
|
162
|
+
if (filterType === FilterTypeEnum.Number && displayValue != null) {
|
|
163
|
+
if (Array.isArray(value) && value.every(v => !isNaN(Number(v)))) {
|
|
164
|
+
displayValue = value.map(v => (typeof v === 'string' ? Number(v) : v));
|
|
165
|
+
}
|
|
166
|
+
else if (typeof displayValue !== 'number') {
|
|
167
|
+
const numValue = +displayValue;
|
|
168
|
+
if (!isNaN(numValue)) {
|
|
169
|
+
displayValue = numValue;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
...filter,
|
|
175
|
+
matchMode,
|
|
176
|
+
value: value,
|
|
177
|
+
displayMatchMode,
|
|
178
|
+
displayValue
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function filterSetStateOnDisplayChange(filter, displayMatchMode, displayValue, filterType, filterDateCfg) {
|
|
182
|
+
let matchMode = displayMatchMode;
|
|
183
|
+
let value = displayValue;
|
|
184
|
+
if (filterType === FilterTypeEnum.Date) {
|
|
185
|
+
if (!filterDateCfg?.valueNoTime && displayValue !== null) {
|
|
186
|
+
if (displayMatchMode === FilterMatchMode.Equals) {
|
|
187
|
+
if (value instanceof Date || typeof value === 'string' || typeof value === 'number') {
|
|
188
|
+
const fromDate = new Date(value);
|
|
189
|
+
const toDate = new Date(value);
|
|
190
|
+
if (filterDateCfg?.showTime) {
|
|
191
|
+
if (filterDateCfg?.showSeconds) {
|
|
192
|
+
fromDate.setMilliseconds(0);
|
|
193
|
+
toDate.setMilliseconds(999);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
fromDate.setSeconds(0, 0);
|
|
197
|
+
toDate.setSeconds(59, 999);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
fromDate.setHours(0, 0, 0, 0);
|
|
202
|
+
toDate.setHours(23, 59, 59, 999);
|
|
203
|
+
}
|
|
204
|
+
value = [fromDate, toDate];
|
|
205
|
+
matchMode = FilterMatchMode.Between;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
value = null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else if (displayMatchMode === FilterMatchMode.Between) {
|
|
212
|
+
if (Array.isArray(value) && value.length === 2 && value.every(i => i instanceof Date || typeof i === 'string' || typeof i === 'number')) {
|
|
213
|
+
const fromDate = new Date(value[0]);
|
|
214
|
+
let toDate = new Date(value[1]);
|
|
215
|
+
if (filterAreDatesEqual(fromDate, toDate, filterDateCfg)) {
|
|
216
|
+
toDate = new Date(fromDate);
|
|
217
|
+
if (filterDateCfg?.showTime) {
|
|
218
|
+
if (filterDateCfg?.showSeconds) {
|
|
219
|
+
toDate.setSeconds(toDate.getSeconds() + 1);
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
toDate.setMinutes(toDate.getMinutes() + 1);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
toDate.setDate(toDate.getDate() + 1);
|
|
227
|
+
}
|
|
228
|
+
value = [fromDate, toDate];
|
|
229
|
+
matchMode = FilterMatchMode.Between;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
value = null;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const convertDateType = filterDateCfg?.valueNoTime ? 'date' : 'date-time';
|
|
238
|
+
const convertDateTimeOpts = {
|
|
239
|
+
utc: filterDateCfg?.valueUtc,
|
|
240
|
+
noMillis: filterDateCfg?.valueNoMillis,
|
|
241
|
+
noTimezone: filterDateCfg?.valueNoTimezone
|
|
242
|
+
};
|
|
243
|
+
value =
|
|
244
|
+
value == null
|
|
245
|
+
? value
|
|
246
|
+
: Array.isArray(value)
|
|
247
|
+
? value.filter(i => i != null).map(i => dateToIsoString(i, convertDateType, convertDateTimeOpts))
|
|
248
|
+
: dateToIsoString(value, convertDateType, convertDateTimeOpts);
|
|
249
|
+
}
|
|
250
|
+
if (matchMode === FilterMatchMode.Exists || matchMode === FilterMatchMode.DoesNotExist) {
|
|
251
|
+
value = null;
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
...filter,
|
|
255
|
+
displayMatchMode: displayMatchMode,
|
|
256
|
+
matchMode: matchMode,
|
|
257
|
+
displayValue: displayValue,
|
|
258
|
+
value: value,
|
|
259
|
+
caseSensitive: filterType === FilterTypeEnum.String ? filter?.caseSensitive : undefined
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function filterAreDatesEqual(fromDate, toDate, filterDateCfg) {
|
|
263
|
+
const startDate = dateToIsoString(fromDate);
|
|
264
|
+
const endDate = dateToIsoString(toDate);
|
|
265
|
+
// 2020-11-02T11:12:12.000
|
|
266
|
+
const cmpLength = filterDateCfg?.showTime ? (filterDateCfg?.showSeconds ? 19 : 16) : 10;
|
|
267
|
+
return startDate.substring(0, cmpLength) === endDate.substring(0, cmpLength);
|
|
268
|
+
}
|
|
269
|
+
function filterApplySerializationConfigToCmp(config, cmpSerCfg) {
|
|
270
|
+
// set default
|
|
271
|
+
cmpSerCfg.dateTimeInUtc = false;
|
|
272
|
+
cmpSerCfg.dateTimeWithTimezone = true;
|
|
273
|
+
cmpSerCfg.dateTimeWithMillis = true;
|
|
274
|
+
cmpSerCfg.filtersDateOnlyDisabled = false;
|
|
275
|
+
// set customizations
|
|
276
|
+
if (config?.serialization) {
|
|
277
|
+
if (config.serialization.dateTimeInUtc !== undefined)
|
|
278
|
+
cmpSerCfg.dateTimeInUtc = config.serialization.dateTimeInUtc;
|
|
279
|
+
if (config.serialization.dateTimeWithTimezone !== undefined)
|
|
280
|
+
cmpSerCfg.dateTimeWithTimezone = config.serialization.dateTimeWithTimezone;
|
|
281
|
+
if (config.serialization.dateTimeWithMillis !== undefined)
|
|
282
|
+
cmpSerCfg.dateTimeWithMillis = config.serialization.dateTimeWithMillis;
|
|
283
|
+
if (config.serialization.filtersDateOnlyDisabled !== undefined)
|
|
284
|
+
cmpSerCfg.filtersDateOnlyDisabled = config.serialization.filtersDateOnlyDisabled;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function filterAdjustDisplayValueOnMatchModeChange(matchMode, value) {
|
|
288
|
+
if (matchMode == null || matchMode === FilterMatchMode.Exists || matchMode === FilterMatchMode.DoesNotExist) {
|
|
289
|
+
return value; // never change, only change later if something else changes here
|
|
290
|
+
}
|
|
291
|
+
if (matchMode === FilterMatchMode.Between) {
|
|
292
|
+
if (!Array.isArray(value)) {
|
|
293
|
+
return value != null ? [value, value] : [];
|
|
294
|
+
}
|
|
295
|
+
else if (value.length === 0 || value.length === 2) {
|
|
296
|
+
return value;
|
|
297
|
+
}
|
|
298
|
+
else if (value.length === 1) {
|
|
299
|
+
return [value[0], value[0]];
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
return [value[0], value[1]];
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (matchMode === FilterMatchMode.In || matchMode === FilterMatchMode.NotIn) {
|
|
306
|
+
return Array.isArray(value) ? value : value == null ? [] : [value];
|
|
307
|
+
}
|
|
308
|
+
return Array.isArray(value) && value.length > 0 ? value[0] : value;
|
|
309
|
+
}
|
|
310
|
+
function filterGetDateConfig(descriptor, serCfg) {
|
|
311
|
+
if (!descriptor || descriptor.filterType !== FilterTypeEnum.Date) {
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
const showTime = descriptor.datePickerShowTime ?? (descriptor.displayFormatApplyToField && descriptor.displayFormat ? angularDateFormatHasTime(descriptor.displayFormat) : false);
|
|
315
|
+
return {
|
|
316
|
+
valueNoTime: descriptor.dateValueNoTime || (!serCfg?.filtersDateOnlyDisabled && !showTime),
|
|
317
|
+
valueUtc: descriptor.dateValueUtc ?? serCfg?.dateTimeInUtc,
|
|
318
|
+
valueNoTimezone: descriptor.dateValueNoTimezone ?? !serCfg?.dateTimeWithTimezone,
|
|
319
|
+
valueNoMillis: !serCfg?.dateTimeWithMillis,
|
|
320
|
+
format: descriptor.datePickerFormat ?? (descriptor.displayFormatApplyToField && descriptor.displayFormat ? fromAngularDateFormatToPrime(descriptor.displayFormat) : undefined),
|
|
321
|
+
showTime: showTime,
|
|
322
|
+
showSeconds: showTime &&
|
|
323
|
+
(descriptor.datePickerShowSeconds ?? (descriptor.displayFormatApplyToField && descriptor.displayFormat ? angularDateFormatHasSeconds(descriptor.displayFormat) : false))
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function filterGetNumberConfig(descriptor) {
|
|
327
|
+
if (!descriptor || descriptor.filterType !== FilterTypeEnum.Number) {
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
const displayCfg = descriptor.displayFormatApplyToField && descriptor.displayFormat ? fromAngularNumberFormatToFractions(descriptor.displayFormat) : undefined;
|
|
331
|
+
return {
|
|
332
|
+
fractionsMin: descriptor.numberMinFractionDigits ?? displayCfg?.fractionsMin,
|
|
333
|
+
fractionsMax: descriptor.numberMaxFractionDigits ?? displayCfg?.fractionsMax
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Creates an array of filter descriptors from an array of generic filter properties.
|
|
338
|
+
*
|
|
339
|
+
* @param {FilterGenericProperty[]} properties - The array of filterable properties, their types and options.
|
|
340
|
+
* @param {LookupDataProviderInst<string, any, any, 'field'>} [valueLookup] - The lookup data provider for value suggestions.
|
|
341
|
+
*/
|
|
342
|
+
function createFilterDescriptorsFromGeneric(properties, valueLookup) {
|
|
343
|
+
return properties.map(genericFilter => {
|
|
344
|
+
// when no generic value lookup is provided, lookup enum filters are treated as string filters
|
|
345
|
+
const filterType = genericFilter.type === FilterTypeEnum.LookupEnum && valueLookup === undefined ? FilterTypeEnum.String : genericFilter.type;
|
|
346
|
+
const filterDescriptor = new FilterDescriptor(genericFilter.property).asFilterType(filterType).asGenericFilter();
|
|
347
|
+
if ((genericFilter.type === FilterTypeEnum.String || genericFilter.type === FilterTypeEnum.LookupEnum) && valueLookup) {
|
|
348
|
+
filterDescriptor.withGenericValueProvider(valueLookup);
|
|
349
|
+
}
|
|
350
|
+
if (genericFilter.opts !== undefined) {
|
|
351
|
+
switch (genericFilter.type) {
|
|
352
|
+
case FilterTypeEnum.Number:
|
|
353
|
+
filterDescriptor.asNumber(genericFilter.opts);
|
|
354
|
+
break;
|
|
355
|
+
case FilterTypeEnum.Date:
|
|
356
|
+
filterDescriptor.asDate(genericFilter.opts);
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
genericFilter.modify?.(filterDescriptor);
|
|
361
|
+
return filterDescriptor;
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
function isFilterValueBlank(value) {
|
|
365
|
+
return value == null || (typeof value === 'string' && value.trim().length === 0) || (Array.isArray(value) && value.length === 0);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
class ADataListService {
|
|
369
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ADataListService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
370
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ADataListService }); }
|
|
371
|
+
}
|
|
372
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ADataListService, decorators: [{
|
|
373
|
+
type: Injectable
|
|
374
|
+
}] });
|
|
375
|
+
|
|
376
|
+
class FilterService {
|
|
377
|
+
#tableData;
|
|
378
|
+
#config;
|
|
379
|
+
#state;
|
|
380
|
+
#tableFilterState;
|
|
381
|
+
constructor() {
|
|
382
|
+
this.#tableData = inject((ADataListService));
|
|
383
|
+
this.#config = signal(undefined, ...(ngDevMode ? [{ debugName: "#config" }] : []));
|
|
384
|
+
this.#state = signal(undefined, ...(ngDevMode ? [{ debugName: "#state" }] : []));
|
|
385
|
+
this.state = this.#state.asReadonly();
|
|
386
|
+
this.isActive = computed(() => this.state()?.matchMode === FilterMatchMode.Exists || this.state()?.matchMode === FilterMatchMode.DoesNotExist || !isFilterValueBlank(this.state()?.value), ...(ngDevMode ? [{ debugName: "isActive" }] : []));
|
|
387
|
+
this.#tableFilterState = computed(() => {
|
|
388
|
+
const property = this.#config()?.descriptor.property;
|
|
389
|
+
return property ? this.#tableData.filterStates()?.[property] : undefined;
|
|
390
|
+
}, ...(ngDevMode ? [{ debugName: "#tableFilterState" }] : []));
|
|
391
|
+
effectWithDeps([this.#config, this.state], ([config, state]) => {
|
|
392
|
+
this.#updateStateIfRequired(config, state, this.#tableFilterState());
|
|
393
|
+
});
|
|
394
|
+
effectWithDeps([this.#tableFilterState], ([currTableFilterState]) => {
|
|
395
|
+
this.#updateStateIfRequired(this.#config(), this.state(), currTableFilterState, false);
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
setConfig(config) {
|
|
399
|
+
this.#config.set(config);
|
|
400
|
+
}
|
|
401
|
+
setMatchMode(displayMatchMode) {
|
|
402
|
+
const config = this.#config();
|
|
403
|
+
if (this.state()?.displayMatchMode === displayMatchMode || config == null) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
this.setState(filterSetStateOnDisplayChange(this.state(), displayMatchMode, filterAdjustDisplayValueOnMatchModeChange(displayMatchMode, this.state()?.displayValue), config.descriptor.filterType, config.dateConfig));
|
|
407
|
+
}
|
|
408
|
+
toggleCaseSensitivity() {
|
|
409
|
+
if (this.#config()?.descriptor.filterType === FilterTypeEnum.String) {
|
|
410
|
+
this.setState({
|
|
411
|
+
...this.state(),
|
|
412
|
+
caseSensitive: !(this.state()?.caseSensitive ?? false)
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
clear() {
|
|
417
|
+
const currConfig = this.#config();
|
|
418
|
+
if (currConfig == null) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const config = { value: null, matchMode: currConfig.defaultMatchMode };
|
|
422
|
+
// set internal filter constraint
|
|
423
|
+
this.setState(filterSetStateOnChange(config, config?.matchMode, config?.value, currConfig.descriptor.filterType, currConfig.dateConfig));
|
|
424
|
+
}
|
|
425
|
+
setDisplayValue(displayValue) {
|
|
426
|
+
const config = this.#config();
|
|
427
|
+
if (config == null) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
this.setState(filterSetStateOnDisplayChange(this.state(), this.state()?.displayMatchMode ?? config.defaultMatchMode, displayValue, config.descriptor.filterType, config.dateConfig));
|
|
431
|
+
}
|
|
432
|
+
setState(state, updateTable = true) {
|
|
433
|
+
const currentMetadata = this.#config();
|
|
434
|
+
if (currentMetadata == null) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (state && !state.displayMatchMode)
|
|
438
|
+
state.displayMatchMode = state.matchMode;
|
|
439
|
+
if (state && !state.displayValue)
|
|
440
|
+
state.displayValue = state.value;
|
|
441
|
+
this.#state.set(state);
|
|
442
|
+
if (updateTable) {
|
|
443
|
+
this.#tableData.updateFilters({ [currentMetadata.descriptor.property]: state });
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
#updateStateIfRequired(config, state, currTableFilterState, updateTable = true) {
|
|
447
|
+
if (config == null) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (!updateTable && currTableFilterState == undefined) {
|
|
451
|
+
currTableFilterState = {};
|
|
452
|
+
}
|
|
453
|
+
if (currTableFilterState && (!state || state.value !== currTableFilterState.value || state.matchMode !== currTableFilterState.matchMode)) {
|
|
454
|
+
this.setState(filterSetStateOnChange(currTableFilterState, currTableFilterState.matchMode, currTableFilterState.value, untracked(() => config.descriptor.filterType), untracked(() => config.dateConfig)), updateTable);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
458
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterService }); }
|
|
459
|
+
}
|
|
460
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterService, decorators: [{
|
|
461
|
+
type: Injectable
|
|
462
|
+
}], ctorParameters: () => [] });
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Cannot be on push change detection strategy because of filter updates triggered from route which causes to force update values in force metadata
|
|
466
|
+
* and these must be propagated through to this component and beyond to primeNG.
|
|
467
|
+
*/
|
|
468
|
+
class TableFilterComponent {
|
|
469
|
+
#el;
|
|
470
|
+
#renderer;
|
|
471
|
+
#overlayService;
|
|
472
|
+
#cd;
|
|
473
|
+
#document;
|
|
474
|
+
#window;
|
|
475
|
+
#overlaySubscription;
|
|
476
|
+
#overlay;
|
|
477
|
+
#scrollHandler;
|
|
478
|
+
#documentClickListener;
|
|
479
|
+
#documentResizeListener;
|
|
480
|
+
#resetSubscription;
|
|
481
|
+
#selfClick;
|
|
482
|
+
#overlayEventListener;
|
|
483
|
+
#numericValueFromModelChange;
|
|
484
|
+
#dateDebounceSubject;
|
|
485
|
+
constructor() {
|
|
486
|
+
this.lookupTypeDropdown = FilterLookupTypeEnum.Dropdown;
|
|
487
|
+
this.lookupTypeAutocomplete = FilterLookupTypeEnum.Autocomplete;
|
|
488
|
+
this.FilterTypeEnum = FilterTypeEnum;
|
|
489
|
+
this.FilterMatchMode = FilterMatchMode;
|
|
490
|
+
this.#el = inject(ElementRef);
|
|
491
|
+
this.#renderer = inject(Renderer2);
|
|
492
|
+
this.#overlayService = inject(OverlayService);
|
|
493
|
+
this.#cd = inject(ChangeDetectorRef);
|
|
494
|
+
this.filter = inject(FilterService);
|
|
495
|
+
this.#document = window.document;
|
|
496
|
+
this.#window = this.#document.defaultView;
|
|
497
|
+
this.config = input.required(...(ngDevMode ? [{ debugName: "config" }] : []));
|
|
498
|
+
this.model = input.required(...(ngDevMode ? [{ debugName: "model" }] : []));
|
|
499
|
+
this.showFilterIcon = input(false, ...(ngDevMode ? [{ debugName: "showFilterIcon", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
500
|
+
this.showTitleAsPlaceholder = input(false, ...(ngDevMode ? [{ debugName: "showTitleAsPlaceholder", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
501
|
+
this.descriptorAsLookup = computed(() => this.config().descriptor instanceof FilterLookupDescriptor ? this.config().descriptor : undefined, ...(ngDevMode ? [{ debugName: "descriptorAsLookup" }] : []));
|
|
502
|
+
this.icon = viewChild('icon', ...(ngDevMode ? [{ debugName: "icon" }] : []));
|
|
503
|
+
this.matchModes = computed(() => this.config().matchModes, ...(ngDevMode ? [{ debugName: "matchModes" }] : []));
|
|
504
|
+
this.isInputDisabled = computed(() => this.filter.state()?.matchMode === FilterMatchMode.Exists || this.filter.state()?.matchMode === FilterMatchMode.DoesNotExist, ...(ngDevMode ? [{ debugName: "isInputDisabled" }] : []));
|
|
505
|
+
this.overlayVisible = signal(false, ...(ngDevMode ? [{ debugName: "overlayVisible" }] : []));
|
|
506
|
+
// display configs
|
|
507
|
+
this.isMultiselect = computed(() => {
|
|
508
|
+
const ft = this.filter.state();
|
|
509
|
+
const matchMode = ft?.displayMatchMode ?? this.config().defaultMatchMode;
|
|
510
|
+
return (matchMode === FilterMatchMode.In || matchMode === FilterMatchMode.NotIn) && (ft?.displayValue == null || Array.isArray(ft.displayValue));
|
|
511
|
+
}, ...(ngDevMode ? [{ debugName: "isMultiselect" }] : []));
|
|
512
|
+
this.placeholderKey = computed(() => {
|
|
513
|
+
const descriptor = this.config().descriptor;
|
|
514
|
+
let defaultPlaceholderKey = 'mngTable.typeToFilter';
|
|
515
|
+
const descriptorAsLookup = this.descriptorAsLookup();
|
|
516
|
+
if (descriptorAsLookup) {
|
|
517
|
+
if (descriptorAsLookup.lookupType === FilterLookupTypeEnum.Autocomplete) {
|
|
518
|
+
defaultPlaceholderKey = 'mngTable.searchToFilter';
|
|
519
|
+
}
|
|
520
|
+
else if (descriptorAsLookup.lookupType === FilterLookupTypeEnum.Dropdown) {
|
|
521
|
+
defaultPlaceholderKey = 'mngTable.selectToFilter';
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
else if (descriptor.filterType === FilterTypeEnum.Boolean) {
|
|
525
|
+
defaultPlaceholderKey = 'mngTable.selectToFilter';
|
|
526
|
+
}
|
|
527
|
+
return this.showTitleAsPlaceholder() ? this.#getPropertyLabelKey(this.config().descriptor) : defaultPlaceholderKey;
|
|
528
|
+
}, ...(ngDevMode ? [{ debugName: "placeholderKey" }] : []));
|
|
529
|
+
this.booleanOptions = [
|
|
530
|
+
{ label: 'general.yes', value: true },
|
|
531
|
+
{ label: 'general.no', value: false }
|
|
532
|
+
];
|
|
533
|
+
this.#numericValueFromModelChange = null;
|
|
534
|
+
this.#dateDebounceSubject = new Subject();
|
|
535
|
+
effectWithDeps([this.config], ([config]) => {
|
|
536
|
+
this.filter.setConfig(config);
|
|
537
|
+
});
|
|
538
|
+
this.#dateDebounceSubject.pipe(debounceTime(500), distinctUntilChanged(), takeUntilDestroyed()).subscribe(v => this.filter.setDisplayValue(v));
|
|
539
|
+
}
|
|
540
|
+
ngOnDestroy() {
|
|
541
|
+
if (this.#overlay) {
|
|
542
|
+
this.#renderer.appendChild(this.#el.nativeElement, this.#overlay);
|
|
543
|
+
ZIndexUtils.clear(this.#overlay);
|
|
544
|
+
this.#onOverlayHide();
|
|
545
|
+
}
|
|
546
|
+
this.#resetSubscription?.unsubscribe();
|
|
547
|
+
this.#overlaySubscription?.unsubscribe();
|
|
548
|
+
}
|
|
549
|
+
onTextModelChange(event) {
|
|
550
|
+
const value = event.target.value;
|
|
551
|
+
if (value === '') {
|
|
552
|
+
this.filter.setDisplayValue(value);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
onTextInputEnterKeyDown(event) {
|
|
556
|
+
const value = event.target.value;
|
|
557
|
+
this.filter.setDisplayValue(value);
|
|
558
|
+
event.preventDefault();
|
|
559
|
+
}
|
|
560
|
+
onNumericModelChange(value) {
|
|
561
|
+
this.#numericValueFromModelChange = value;
|
|
562
|
+
if (value === null) {
|
|
563
|
+
this.filter.setDisplayValue(value);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
onNumericInputKeyDown(event) {
|
|
567
|
+
if (event.key === 'Enter') {
|
|
568
|
+
if (this.filter.state()?.displayMatchMode === FilterMatchMode.Between && Array.isArray(this.#numericValueFromModelChange)) {
|
|
569
|
+
const numberValues = this.#numericValueFromModelChange.filter(v => typeof v === 'number');
|
|
570
|
+
if (numberValues.length !== 2) {
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
this.filter.setDisplayValue(this.#numericValueFromModelChange);
|
|
575
|
+
event.preventDefault();
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
onDateFilterModelChange(value) {
|
|
579
|
+
if (this.filter.state()?.displayMatchMode === FilterMatchMode.Between && Array.isArray(value)) {
|
|
580
|
+
const dateValues = value.filter(v => v instanceof Date);
|
|
581
|
+
if (dateValues.length !== 2) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
this.#dateDebounceSubject.next(value);
|
|
586
|
+
}
|
|
587
|
+
booleanFilter(value) {
|
|
588
|
+
this.filter.setDisplayValue(value);
|
|
589
|
+
}
|
|
590
|
+
autocompleteFilter(value) {
|
|
591
|
+
this.filter.setDisplayValue(value);
|
|
592
|
+
}
|
|
593
|
+
dropdownFilter(value) {
|
|
594
|
+
this.filter.setDisplayValue(value);
|
|
595
|
+
}
|
|
596
|
+
onMatchModeChange(displayMatchMode) {
|
|
597
|
+
this.filter.setMatchMode(displayMatchMode);
|
|
598
|
+
this.#hideOverlay();
|
|
599
|
+
}
|
|
600
|
+
onMatchModeKeyDown(event) {
|
|
601
|
+
const item = event.target;
|
|
602
|
+
switch (event.key) {
|
|
603
|
+
case 'ArrowDown':
|
|
604
|
+
// eslint-disable-next-line no-case-declarations
|
|
605
|
+
const nextItem = this.#findNextMenuModeItem(item);
|
|
606
|
+
if (nextItem) {
|
|
607
|
+
item.removeAttribute('tabindex');
|
|
608
|
+
nextItem.tabIndex = '0';
|
|
609
|
+
nextItem.focus();
|
|
610
|
+
}
|
|
611
|
+
event.preventDefault();
|
|
612
|
+
break;
|
|
613
|
+
case 'ArrowUp':
|
|
614
|
+
// eslint-disable-next-line no-case-declarations
|
|
615
|
+
const prevItem = this.#findPrevMenuModeItem(item);
|
|
616
|
+
if (prevItem) {
|
|
617
|
+
item.removeAttribute('tabindex');
|
|
618
|
+
prevItem.tabIndex = '0';
|
|
619
|
+
prevItem.focus();
|
|
620
|
+
}
|
|
621
|
+
event.preventDefault();
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
onCaseSensitivityToggle() {
|
|
626
|
+
this.filter.toggleCaseSensitivity();
|
|
627
|
+
}
|
|
628
|
+
clear() {
|
|
629
|
+
this.filter.clear();
|
|
630
|
+
this.#hideOverlay();
|
|
631
|
+
}
|
|
632
|
+
toggleMenu(event) {
|
|
633
|
+
this.overlayVisible.set(!this.overlayVisible());
|
|
634
|
+
event.stopPropagation();
|
|
635
|
+
}
|
|
636
|
+
onToggleButtonKeyDown(event) {
|
|
637
|
+
switch (event.key) {
|
|
638
|
+
case 'Escape':
|
|
639
|
+
case 'Tab':
|
|
640
|
+
this.overlayVisible.set(false);
|
|
641
|
+
break;
|
|
642
|
+
case 'ArrowDown':
|
|
643
|
+
if (this.overlayVisible()) {
|
|
644
|
+
const focusable = DomHandler.getFocusableElements(this.#overlay);
|
|
645
|
+
if (focusable) {
|
|
646
|
+
focusable[0].focus();
|
|
647
|
+
}
|
|
648
|
+
event.preventDefault();
|
|
649
|
+
}
|
|
650
|
+
else if (event.altKey) {
|
|
651
|
+
this.overlayVisible.set(true);
|
|
652
|
+
event.preventDefault();
|
|
653
|
+
}
|
|
654
|
+
break;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
onEscape() {
|
|
658
|
+
this.overlayVisible.set(false);
|
|
659
|
+
}
|
|
660
|
+
onContentClick() {
|
|
661
|
+
this.#selfClick = true;
|
|
662
|
+
}
|
|
663
|
+
// onOverlayAnimationStart(event: AnimationEvent) {
|
|
664
|
+
onOverlayAnimationStart(event) {
|
|
665
|
+
switch (event.toState) {
|
|
666
|
+
case 'visible':
|
|
667
|
+
this.#overlay = event.element;
|
|
668
|
+
this.#renderer.appendChild(this.#document.body, this.#overlay);
|
|
669
|
+
// instead of following (commented) line, we use the one below to set z-index of overlay to 1000 (which is primeNG default)
|
|
670
|
+
// ZIndexUtils.set('overlay', this.#overlay, this.#tableMetadata.primeConfig.zIndex.overlay);
|
|
671
|
+
ZIndexUtils.set('overlay', this.#overlay, 1000);
|
|
672
|
+
DomHandler.absolutePosition(this.#overlay, this.icon()?.nativeElement);
|
|
673
|
+
this.#bindDocumentClickListener();
|
|
674
|
+
this.#bindDocumentResizeListener();
|
|
675
|
+
this.#bindScrollListener();
|
|
676
|
+
this.#overlayEventListener = (e) => {
|
|
677
|
+
if (this.#overlay && this.#overlay.contains(e.target)) {
|
|
678
|
+
this.#selfClick = true;
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
this.#overlaySubscription = this.#overlayService.clickObservable.subscribe(this.#overlayEventListener);
|
|
682
|
+
break;
|
|
683
|
+
case 'void':
|
|
684
|
+
this.#onOverlayHide();
|
|
685
|
+
this.#overlaySubscription?.unsubscribe();
|
|
686
|
+
break;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// onOverlayAnimationEnd(event: AnimationEvent) {
|
|
690
|
+
onOverlayAnimationEnd(event) {
|
|
691
|
+
switch (event.toState) {
|
|
692
|
+
case 'void':
|
|
693
|
+
ZIndexUtils.clear(event.element);
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
#findNextMenuModeItem(item) {
|
|
698
|
+
const nextItem = item.nextElementSibling;
|
|
699
|
+
if (nextItem)
|
|
700
|
+
return DomHandler.hasClass(nextItem, 'p-column-filter-separator') ? this.#findNextMenuModeItem(nextItem) : nextItem;
|
|
701
|
+
else
|
|
702
|
+
return item.parentElement?.firstElementChild;
|
|
703
|
+
}
|
|
704
|
+
#findPrevMenuModeItem(item) {
|
|
705
|
+
const prevItem = item.previousElementSibling;
|
|
706
|
+
if (prevItem)
|
|
707
|
+
return DomHandler.hasClass(prevItem, 'p-column-filter-separator') ? this.#findPrevMenuModeItem(prevItem) : prevItem;
|
|
708
|
+
else
|
|
709
|
+
return item.parentElement?.lastElementChild;
|
|
710
|
+
}
|
|
711
|
+
#isOutsideClicked(event) {
|
|
712
|
+
return !(this.#overlay?.isSameNode(event.target) ||
|
|
713
|
+
this.#overlay?.contains(event.target) ||
|
|
714
|
+
this.icon()?.nativeElement.isSameNode(event.target) ||
|
|
715
|
+
this.icon()?.nativeElement.contains(event.target) ||
|
|
716
|
+
DomHandler.hasClass(event.target, 'p-column-filter-add-button') ||
|
|
717
|
+
DomHandler.hasClass(event.target.parentElement, 'p-column-filter-add-button') ||
|
|
718
|
+
DomHandler.hasClass(event.target, 'p-column-filter-remove-button') ||
|
|
719
|
+
DomHandler.hasClass(event.target.parentElement, 'p-column-filter-remove-button'));
|
|
720
|
+
}
|
|
721
|
+
#bindDocumentClickListener() {
|
|
722
|
+
if (!this.#documentClickListener) {
|
|
723
|
+
const documentTarget = this.#el ? this.#el.nativeElement.ownerDocument : 'document';
|
|
724
|
+
this.#documentClickListener = this.#renderer.listen(documentTarget, 'click', event => {
|
|
725
|
+
if (this.overlayVisible() && !this.#selfClick && this.#isOutsideClicked(event)) {
|
|
726
|
+
this.#hideOverlay();
|
|
727
|
+
}
|
|
728
|
+
this.#selfClick = false;
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
#unbindDocumentClickListener() {
|
|
733
|
+
if (this.#documentClickListener) {
|
|
734
|
+
this.#documentClickListener();
|
|
735
|
+
this.#documentClickListener = null;
|
|
736
|
+
this.#selfClick = false;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
#bindDocumentResizeListener() {
|
|
740
|
+
if (!this.#documentResizeListener) {
|
|
741
|
+
this.#documentResizeListener = this.#renderer.listen(this.#window, 'resize', () => {
|
|
742
|
+
if (this.overlayVisible() && !DomHandler.isTouchDevice()) {
|
|
743
|
+
this.#hideOverlay();
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
#unbindDocumentResizeListener() {
|
|
749
|
+
if (this.#documentResizeListener) {
|
|
750
|
+
this.#documentResizeListener();
|
|
751
|
+
this.#documentResizeListener = null;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
#bindScrollListener() {
|
|
755
|
+
if (!this.#scrollHandler) {
|
|
756
|
+
this.#scrollHandler = new ConnectedOverlayScrollHandler(this.icon()?.nativeElement, () => {
|
|
757
|
+
if (this.overlayVisible()) {
|
|
758
|
+
this.#hideOverlay();
|
|
759
|
+
}
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
this.#scrollHandler.bindScrollListener();
|
|
763
|
+
}
|
|
764
|
+
#unbindScrollListener() {
|
|
765
|
+
if (this.#scrollHandler) {
|
|
766
|
+
this.#scrollHandler.unbindScrollListener();
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
#hideOverlay() {
|
|
770
|
+
this.overlayVisible.set(false);
|
|
771
|
+
this.#cd.markForCheck();
|
|
772
|
+
}
|
|
773
|
+
#onOverlayHide() {
|
|
774
|
+
this.#unbindDocumentClickListener();
|
|
775
|
+
this.#unbindDocumentResizeListener();
|
|
776
|
+
this.#unbindScrollListener();
|
|
777
|
+
this.#overlay = null;
|
|
778
|
+
}
|
|
779
|
+
#getPropertyLabelKey(filterDescriptor) {
|
|
780
|
+
let labelKey;
|
|
781
|
+
if (filterDescriptor.title !== undefined && !filterDescriptor.titleUseModelBase) {
|
|
782
|
+
labelKey = filterDescriptor.title;
|
|
783
|
+
}
|
|
784
|
+
else {
|
|
785
|
+
labelKey = getI18nTypePropertyKey(this.model().i18nBaseKey, filterDescriptor.title ?? filterDescriptor.property);
|
|
786
|
+
}
|
|
787
|
+
return labelKey;
|
|
788
|
+
}
|
|
789
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
790
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableFilterComponent, isStandalone: true, selector: "mng-table-filter", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, showFilterIcon: { classPropertyName: "showFilterIcon", publicName: "showFilterIcon", isSignal: true, isRequired: false, transformFunction: null }, showTitleAsPlaceholder: { classPropertyName: "showTitleAsPlaceholder", publicName: "showTitleAsPlaceholder", isSignal: true, isRequired: false, transformFunction: null } }, providers: [FilterService], viewQueries: [{ propertyName: "icon", first: true, predicate: ["icon"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"flex items-center\">\n @let requiredFilterMissing = config().descriptor.isRequired && !filter.isActive();\n @let placeholder = (placeholderKey() | translate) + (config().descriptor.isRequired ? ' *' : '');\n <div\n class=\"flex items-center [&_p-inputgroup-addon]:p-0!\"\n [class.mng-filter-active]=\"filter.isActive()\"\n [class.[&_*]:border-red-500!]=\"requiredFilterMissing\"\n [class.mng-filter-required]=\"requiredFilterMissing\">\n @switch (config().descriptor.filterType) {\n @case (FilterTypeEnum.Number) {\n @if (filter.state()?.displayMatchMode === 'between') {\n <mng-number-range\n vertical=\"true\"\n className=\"mng-filter-number\"\n [ngModel]=\"filter.state()?.displayValue\"\n (ngModelChange)=\"onNumericModelChange($event)\"\n (keyDown)=\"onNumericInputKeyDown($event)\"\n [placeholder]=\"placeholder\"\n [useGrouping]=\"config().descriptor.numberUseGrouping\"\n [minFractionDigits]=\"config().numberConfig?.fractionsMin\"\n [maxFractionDigits]=\"config().numberConfig?.fractionsMax\"\n [disabled]=\"isInputDisabled()\"\n [templates]=\"showFilterIcon() ? [numberRangePrependIcon] : []\" />\n } @else {\n <p-inputgroup>\n @if (showFilterIcon()) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </p-inputgroup-addon>\n }\n <p-inputNumber\n inputStyleClass=\"mng-filter-number\"\n [ngModel]=\"filter.state()?.displayValue\"\n (ngModelChange)=\"onNumericModelChange($event)\"\n (onKeyDown)=\"onNumericInputKeyDown($event)\"\n [placeholder]=\"placeholder\"\n [useGrouping]=\"config().descriptor.numberUseGrouping\"\n [minFractionDigits]=\"config().numberConfig?.fractionsMin\"\n [maxFractionDigits]=\"config().numberConfig?.fractionsMax\"\n [disabled]=\"isInputDisabled()\" />\n </p-inputgroup>\n }\n }\n\n @case (FilterTypeEnum.Boolean) {\n <mng-dropdown\n optionsLabelProperty=\"label\"\n optionsValueProperty=\"value\"\n [ngModel]=\"filter.state()?.displayValue\"\n [options]=\"booleanOptions\"\n [optionsLabelTranslate]=\"true\"\n [placeholder]=\"placeholder\"\n [disabled]=\"isInputDisabled()\"\n (valueChange)=\"booleanFilter($event)\"\n [templates]=\"showFilterIcon() ? [dropdownPrependIcon] : []\">\n </mng-dropdown>\n }\n @case (FilterTypeEnum.Date) {\n @if (filter.state()?.displayMatchMode === FilterMatchMode.Between) {\n <mng-date-range\n vertical=\"true\"\n [ngModel]=\"filter.state()?.displayValue\"\n (ngModelChange)=\"onDateFilterModelChange($event)\"\n [inputStyleClass]=\"showFilterIcon() ? '!rounded-s-none' : ''\"\n [showTime]=\"config().dateConfig?.showTime ?? false\"\n [showSeconds]=\"config().dateConfig?.showSeconds ?? false\"\n [dateFormat]=\"config().dateConfig?.format\"\n [placeholder]=\"placeholder\"\n [disabled]=\"isInputDisabled()\"\n [templates]=\"showFilterIcon() ? [dateRangePrependIcon] : []\" />\n } @else {\n <p-inputgroup>\n @if (showFilterIcon()) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </p-inputgroup-addon>\n }\n <mng-datetime-picker\n [ngModel]=\"filter.state()?.displayValue\"\n (ngModelChange)=\"onDateFilterModelChange($event)\"\n [inputStyleClass]=\"showFilterIcon() ? '!rounded-s-none' : ''\"\n [placeholder]=\"placeholder\"\n showIcon=\"true\"\n [time]=\"config().dateConfig?.showTime ?? false\"\n [seconds]=\"config().dateConfig?.showSeconds ?? false\"\n [milliseconds]=\"config().dateConfig?.showMilliseconds ?? false\"\n [primeTimePicker]=\"config().dateConfig?.primeTimePicker ?? false\"\n [timeSelect]=\"config().dateConfig?.timeSelect ?? true\"\n [timeSelectInterval]=\"config().dateConfig?.timeSelectInterval ?? 60\"\n [dateFormat]=\"config().dateConfig?.format\"\n required=\"true\" />\n </p-inputgroup>\n }\n }\n @case (FilterTypeEnum.Lookup) {\n <ng-container *ngTemplateOutlet=\"lookupFilter\" />\n }\n @case (FilterTypeEnum.LookupEnum) {\n <ng-container *ngTemplateOutlet=\"lookupFilter\" />\n }\n @default {\n <p-inputgroup>\n @if (showFilterIcon()) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </p-inputgroup-addon>\n }\n <input\n type=\"text\"\n pInputText\n class=\"mng-filter-string\"\n [value]=\"filter.state()?.displayValue ?? ''\"\n [disabled]=\"isInputDisabled()\"\n (input)=\"onTextModelChange($event)\"\n (keydown.enter)=\"onTextInputEnterKeyDown($event)\"\n [attr.placeholder]=\"placeholder\"\n [mngInputTrim]=\"config().descriptor.trimOption\" />\n </p-inputgroup>\n }\n }\n\n <ng-template #lookupFilter>\n @if (descriptorAsLookup(); as lookup) {\n @switch (lookup.lookupType) {\n @case (lookupTypeAutocomplete) {\n <mng-autocomplete\n *mngRerender=\"isMultiselect()\"\n [ngModel]=\"filter.state()?.displayValue\"\n [dataProvider]=\"lookup.dataProvider\"\n [optionsTrackProperty]=\"lookup.optionsValueProperty\"\n [optionsValueProperty]=\"lookup.optionsValueProperty\"\n [optionsLabelProperty]=\"lookup.optionsLabelProperty\"\n [optionsLabelTranslate]=\"lookup.optionsLabelTranslate\"\n [multiselect]=\"isMultiselect()\"\n [autoClear]=\"lookup.autocompleteAutoClear ?? false\"\n [openOnFocus]=\"lookup.autocompleteAutoClear ?? true\"\n [inlineSearch]=\"lookup.autocompleteInlineSearch ?? false\"\n [placeholder]=\"placeholder\"\n [className]=\"lookup.className\"\n [dropdownClassName]=\"lookup.dropdownClassName\"\n [disabled]=\"isInputDisabled()\"\n (valueChange)=\"autocompleteFilter($event)\"\n [searchTrim]=\"config().descriptor.trimOption\"\n [templates]=\"showFilterIcon() ? [autocompletePrependIcon] : []\">\n </mng-autocomplete>\n }\n @case (lookupTypeDropdown) {\n <mng-dropdown\n *mngRerender=\"isMultiselect()\"\n [ngModel]=\"filter.state()?.displayValue\"\n [dataProvider]=\"lookup.dataProvider\"\n [optionsValueProperty]=\"lookup.optionsValueProperty\"\n [optionsLabelProperty]=\"lookup.optionsLabelProperty\"\n [optionsLabelTranslate]=\"lookup.optionsLabelTranslate\"\n [multiselect]=\"isMultiselect()\"\n [placeholder]=\"placeholder\"\n [className]=\"lookup.className\"\n [dropdownClassName]=\"lookup.dropdownClassName\"\n [showClear]=\"false\"\n [changeValueOnBlur]=\"isMultiselect()\"\n [disabled]=\"isInputDisabled()\"\n (valueChange)=\"dropdownFilter($event)\"\n [templates]=\"showFilterIcon() ? [dropdownPrependIcon] : []\">\n </mng-dropdown>\n }\n }\n }\n </ng-template>\n\n <ng-template mngAutocompleteTemplate name=\"prepend\" #autocompletePrependIcon=\"mngAutocompleteTemplate\">\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </ng-template>\n <ng-template mngDropdownTemplate name=\"prepend\" #dropdownPrependIcon=\"mngDropdownTemplate\">\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </ng-template>\n <ng-template mngDateRangeTemplate name=\"prepend\" #dateRangePrependIcon=\"mngDateRangeTemplate\">\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </ng-template>\n <ng-template mngNumberRangeTemplate name=\"prepend\" #numberRangePrependIcon=\"mngNumberRangeTemplate\">\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </ng-template>\n\n <ng-template #iconTemplate>\n <button\n #icon\n class=\"mng-filter-options mng-filter-icon cursor-pointer pi pi-filter w-full h-full rounded-tl-md rounded-bl-md\"\n (click)=\"toggleMenu($event)\"\n (keydown)=\"onToggleButtonKeyDown($event)\"></button>\n </ng-template>\n\n @if (overlayVisible()) {\n <div\n class=\"p-datatable-filter-overlay\"\n (click)=\"onContentClick()\"\n [@overlayAnimation]=\"'visible'\"\n (@overlayAnimation.start)=\"onOverlayAnimationStart($event)\"\n (@overlayAnimation.done)=\"onOverlayAnimationEnd($event)\"\n (keydown.escape)=\"onEscape()\">\n <ul class=\"p-datatable-filter-constraint-list\">\n @for (matchMode of matchModes(); track matchMode; let i = $index) {\n <li\n class=\"p-datatable-filter-constraint\"\n [class.p-datatable-filter-constraint-selected]=\"matchMode.value === filter.state()?.displayMatchMode\"\n (click)=\"onMatchModeChange(matchMode.value)\"\n (keydown)=\"onMatchModeKeyDown($event)\"\n (keydown.enter)=\"this.onMatchModeChange(matchMode.value)\"\n [attr.tabindex]=\"i === 0 ? '0' : null\">\n {{ matchMode.label }}\n </li>\n }\n @if (config().descriptor.filterType === FilterTypeEnum.String) {\n <li class=\"p-datatable-filter-constraint-separator\" (keydown)=\"onMatchModeKeyDown($event)\"></li>\n <li\n class=\"p-datatable-filter-constraint\"\n (click)=\"onCaseSensitivityToggle()\"\n (keydown)=\"onMatchModeKeyDown($event)\"\n (keydown.enter)=\"onCaseSensitivityToggle()\">\n <div class=\"flex items-center\">\n <span class=\"mr-2\"> {{ 'mngFilter.caseSensitive' | translate }} </span>\n <p-toggle-switch [ngModel]=\"filter.state()?.caseSensitive || false\" class=\"ml-auto pointer-events-none\"></p-toggle-switch>\n </div>\n </li>\n }\n <li class=\"p-datatable-filter-constraint-separator\" (keydown)=\"onMatchModeKeyDown($event)\"></li>\n <li class=\"p-datatable-filter-constraint\" (click)=\"clear()\" (keydown)=\"onMatchModeKeyDown($event)\" (keydown.enter)=\"clear()\">\n {{ 'mngPrime.noFilter' | translate }}\n </li>\n </ul>\n </div>\n }\n </div>\n\n @if (!showFilterIcon()) {\n <button\n #icon\n class=\"mng-filter-options cursor-pointer ml-1\"\n [ngClass]=\"{\n 'text-primary': filter.isActive(),\n 'text-slate-400': !filter.isActive()\n }\"\n (click)=\"toggleMenu($event)\"\n (keydown)=\"onToggleButtonKeyDown($event)\">\n <i class=\"pi pi-ellipsis-v\"></i>\n </button>\n }\n</div>\n", styles: ["mng-table-filter{--filter-active-bg: var(--color-primary-50);--filter-active-color: var(--color-primary-600)}mng-table-filter .mng-filter-string{min-width:135px}mng-table-filter .mng-filter-number{min-width:165px}mng-table-filter .mng-filter-date{min-width:170px}mng-table-filter .mng-filter-boolean{min-width:80px}mng-table-filter .mng-filter-lookup,mng-table-filter .mng-filter-lookupenum{min-width:180px}mng-table-filter .mng-filter-required{position:relative}mng-table-filter p-tag.mng-filter-required{border:1px solid var(--color-red-500)}mng-table-filter .mng-filter-required:after{content:\"\";position:absolute;top:0;right:0;width:1rem;height:1rem;background-color:var(--color-red-500);z-index:1;clip-path:polygon(0 0,100% 0,100% 100%,0 0);border-top-right-radius:var(--p-inputgroup-addon-border-radius)}mng-table-filter .mng-filter-icon{color:var(--p-inputgroup-addon-color)}mng-table-filter .mng-filter-icon:hover{background:var(--p-select-filled-hover-background)}mng-table-filter .mng-filter-active *{border-color:var(--filter-active-color)!important}mng-table-filter .mng-filter-active p-inputgroup-addon,mng-table-filter .mng-filter-active input,mng-table-filter .mng-filter-active p-select,mng-table-filter .mng-filter-active p-multiselect,mng-table-filter .mng-filter-active .p-autocomplete-input-multiple{background:var(--filter-active-bg)}mng-table-filter .mng-filter-active .mng-filter-icon{color:var(--filter-active-color)}:root[class*=app-dark] mng-table-filter{--filter-active-bg: var(--p-surface-800);--filter-active-color: var(--p-surface-400)}\n"], dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: DateRangeComponent, selector: "mng-date-range", inputs: ["placeholder", "showTime", "showSeconds", "milliseconds", "primeTimePicker", "timeSelect", "timeSelectInterval", "dateFormat", "className", "inputStyleClass", "required", "disabled", "vertical", "templates"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: AutocompleteComponent, selector: "mng-autocomplete", inputs: ["dataProvider", "optionsTrackProperty", "optionsValueProperty", "optionsLabelProperty", "optionsLabelTranslate", "inlineSearch", "openOnFocus", "multiselect", "placeholder", "className", "dropdownClassName", "showClear", "autoClear", "selectFirst", "searchTrim", "disabled", "templates"], outputs: ["valueChange", "blur"] }, { kind: "component", type: DropdownComponent, selector: "mng-dropdown", inputs: ["dataProvider", "options", "optionsTrackProperty", "optionsLabelProperty", "optionsLabelTranslate", "optionsValueProperty", "optionsDisabledProperty", "multiselect", "placeholder", "showClear", "selectFirstItem", "className", "dropdownClassName", "changeValueOnBlur", "loading", "disabled", "allowInput", "appendTo", "templates", "inlineSearch", "searchTrim"], outputs: ["valueChange", "blur"] }, { kind: "component", type: InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: InputTrimDirective, selector: "[mngInputTrim]", inputs: ["mngInputTrim"] }, { kind: "component", type: NumberRangeComponent, selector: "mng-number-range", inputs: ["placeholder", "useGrouping", "minFractionDigits", "maxFractionDigits", "required", "disabled", "vertical", "templates", "className"], outputs: ["keyDown"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: RerenderDirective, selector: "[mngRerender]", inputs: ["mngRerender"] }, { kind: "component", type: InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "component", type: InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["styleClass", "tabindex", "inputId", "readonly", "trueValue", "falseValue", "ariaLabel", "size", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "directive", type: AutocompleteTemplateDirective, selector: "[mngAutocompleteTemplate]", inputs: ["name"], exportAs: ["mngAutocompleteTemplate"] }, { kind: "directive", type: DropdownTemplateDirective, selector: "[mngDropdownTemplate]", inputs: ["name"], exportAs: ["mngDropdownTemplate"] }, { kind: "directive", type: DateRangeTemplateDirective, selector: "[mngDateRangeTemplate]", inputs: ["name"], exportAs: ["mngDateRangeTemplate"] }, { kind: "directive", type: NumberRangeTemplateDirective, selector: "[mngNumberRangeTemplate]", inputs: ["name"], exportAs: ["mngNumberRangeTemplate"] }, { kind: "component", type: DatetimePickerComponent, selector: "mng-datetime-picker", inputs: ["templates", "time", "timeSelect", "timeSelectInterval", "seconds", "milliseconds", "primeTimePicker", "dateFormat", "placeholder", "minDate", "maxDate", "disabled", "required", "showIcon", "showButtonBar", "showClear", "className", "panelStyleClass", "inputStyleClass", "dateRange"], outputs: ["blur"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], animations: [
|
|
791
|
+
trigger('overlayAnimation', [
|
|
792
|
+
transition(':enter', [style({ opacity: 0, transform: 'scaleY(0.8)' }), animate('.12s cubic-bezier(0, 0, 0.2, 1)')]),
|
|
793
|
+
transition(':leave', [animate('.1s linear', style({ opacity: 0 }))])
|
|
794
|
+
])
|
|
795
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
796
|
+
}
|
|
797
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterComponent, decorators: [{
|
|
798
|
+
type: Component,
|
|
799
|
+
args: [{ selector: 'mng-table-filter', imports: [
|
|
800
|
+
TableModule,
|
|
801
|
+
TranslatePipe,
|
|
802
|
+
DateRangeComponent,
|
|
803
|
+
FormsModule,
|
|
804
|
+
AutocompleteComponent,
|
|
805
|
+
DropdownComponent,
|
|
806
|
+
InputNumber,
|
|
807
|
+
InputText,
|
|
808
|
+
InputTrimDirective,
|
|
809
|
+
NumberRangeComponent,
|
|
810
|
+
NgTemplateOutlet,
|
|
811
|
+
RerenderDirective,
|
|
812
|
+
InputGroup,
|
|
813
|
+
InputGroupAddon,
|
|
814
|
+
NgClass,
|
|
815
|
+
ToggleSwitch,
|
|
816
|
+
AutocompleteTemplateDirective,
|
|
817
|
+
DropdownTemplateDirective,
|
|
818
|
+
DateRangeTemplateDirective,
|
|
819
|
+
NumberRangeTemplateDirective,
|
|
820
|
+
DatetimePickerComponent
|
|
821
|
+
], animations: [
|
|
822
|
+
trigger('overlayAnimation', [
|
|
823
|
+
transition(':enter', [style({ opacity: 0, transform: 'scaleY(0.8)' }), animate('.12s cubic-bezier(0, 0, 0.2, 1)')]),
|
|
824
|
+
transition(':leave', [animate('.1s linear', style({ opacity: 0 }))])
|
|
825
|
+
])
|
|
826
|
+
], providers: [FilterService], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex items-center\">\n @let requiredFilterMissing = config().descriptor.isRequired && !filter.isActive();\n @let placeholder = (placeholderKey() | translate) + (config().descriptor.isRequired ? ' *' : '');\n <div\n class=\"flex items-center [&_p-inputgroup-addon]:p-0!\"\n [class.mng-filter-active]=\"filter.isActive()\"\n [class.[&_*]:border-red-500!]=\"requiredFilterMissing\"\n [class.mng-filter-required]=\"requiredFilterMissing\">\n @switch (config().descriptor.filterType) {\n @case (FilterTypeEnum.Number) {\n @if (filter.state()?.displayMatchMode === 'between') {\n <mng-number-range\n vertical=\"true\"\n className=\"mng-filter-number\"\n [ngModel]=\"filter.state()?.displayValue\"\n (ngModelChange)=\"onNumericModelChange($event)\"\n (keyDown)=\"onNumericInputKeyDown($event)\"\n [placeholder]=\"placeholder\"\n [useGrouping]=\"config().descriptor.numberUseGrouping\"\n [minFractionDigits]=\"config().numberConfig?.fractionsMin\"\n [maxFractionDigits]=\"config().numberConfig?.fractionsMax\"\n [disabled]=\"isInputDisabled()\"\n [templates]=\"showFilterIcon() ? [numberRangePrependIcon] : []\" />\n } @else {\n <p-inputgroup>\n @if (showFilterIcon()) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </p-inputgroup-addon>\n }\n <p-inputNumber\n inputStyleClass=\"mng-filter-number\"\n [ngModel]=\"filter.state()?.displayValue\"\n (ngModelChange)=\"onNumericModelChange($event)\"\n (onKeyDown)=\"onNumericInputKeyDown($event)\"\n [placeholder]=\"placeholder\"\n [useGrouping]=\"config().descriptor.numberUseGrouping\"\n [minFractionDigits]=\"config().numberConfig?.fractionsMin\"\n [maxFractionDigits]=\"config().numberConfig?.fractionsMax\"\n [disabled]=\"isInputDisabled()\" />\n </p-inputgroup>\n }\n }\n\n @case (FilterTypeEnum.Boolean) {\n <mng-dropdown\n optionsLabelProperty=\"label\"\n optionsValueProperty=\"value\"\n [ngModel]=\"filter.state()?.displayValue\"\n [options]=\"booleanOptions\"\n [optionsLabelTranslate]=\"true\"\n [placeholder]=\"placeholder\"\n [disabled]=\"isInputDisabled()\"\n (valueChange)=\"booleanFilter($event)\"\n [templates]=\"showFilterIcon() ? [dropdownPrependIcon] : []\">\n </mng-dropdown>\n }\n @case (FilterTypeEnum.Date) {\n @if (filter.state()?.displayMatchMode === FilterMatchMode.Between) {\n <mng-date-range\n vertical=\"true\"\n [ngModel]=\"filter.state()?.displayValue\"\n (ngModelChange)=\"onDateFilterModelChange($event)\"\n [inputStyleClass]=\"showFilterIcon() ? '!rounded-s-none' : ''\"\n [showTime]=\"config().dateConfig?.showTime ?? false\"\n [showSeconds]=\"config().dateConfig?.showSeconds ?? false\"\n [dateFormat]=\"config().dateConfig?.format\"\n [placeholder]=\"placeholder\"\n [disabled]=\"isInputDisabled()\"\n [templates]=\"showFilterIcon() ? [dateRangePrependIcon] : []\" />\n } @else {\n <p-inputgroup>\n @if (showFilterIcon()) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </p-inputgroup-addon>\n }\n <mng-datetime-picker\n [ngModel]=\"filter.state()?.displayValue\"\n (ngModelChange)=\"onDateFilterModelChange($event)\"\n [inputStyleClass]=\"showFilterIcon() ? '!rounded-s-none' : ''\"\n [placeholder]=\"placeholder\"\n showIcon=\"true\"\n [time]=\"config().dateConfig?.showTime ?? false\"\n [seconds]=\"config().dateConfig?.showSeconds ?? false\"\n [milliseconds]=\"config().dateConfig?.showMilliseconds ?? false\"\n [primeTimePicker]=\"config().dateConfig?.primeTimePicker ?? false\"\n [timeSelect]=\"config().dateConfig?.timeSelect ?? true\"\n [timeSelectInterval]=\"config().dateConfig?.timeSelectInterval ?? 60\"\n [dateFormat]=\"config().dateConfig?.format\"\n required=\"true\" />\n </p-inputgroup>\n }\n }\n @case (FilterTypeEnum.Lookup) {\n <ng-container *ngTemplateOutlet=\"lookupFilter\" />\n }\n @case (FilterTypeEnum.LookupEnum) {\n <ng-container *ngTemplateOutlet=\"lookupFilter\" />\n }\n @default {\n <p-inputgroup>\n @if (showFilterIcon()) {\n <p-inputgroup-addon>\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </p-inputgroup-addon>\n }\n <input\n type=\"text\"\n pInputText\n class=\"mng-filter-string\"\n [value]=\"filter.state()?.displayValue ?? ''\"\n [disabled]=\"isInputDisabled()\"\n (input)=\"onTextModelChange($event)\"\n (keydown.enter)=\"onTextInputEnterKeyDown($event)\"\n [attr.placeholder]=\"placeholder\"\n [mngInputTrim]=\"config().descriptor.trimOption\" />\n </p-inputgroup>\n }\n }\n\n <ng-template #lookupFilter>\n @if (descriptorAsLookup(); as lookup) {\n @switch (lookup.lookupType) {\n @case (lookupTypeAutocomplete) {\n <mng-autocomplete\n *mngRerender=\"isMultiselect()\"\n [ngModel]=\"filter.state()?.displayValue\"\n [dataProvider]=\"lookup.dataProvider\"\n [optionsTrackProperty]=\"lookup.optionsValueProperty\"\n [optionsValueProperty]=\"lookup.optionsValueProperty\"\n [optionsLabelProperty]=\"lookup.optionsLabelProperty\"\n [optionsLabelTranslate]=\"lookup.optionsLabelTranslate\"\n [multiselect]=\"isMultiselect()\"\n [autoClear]=\"lookup.autocompleteAutoClear ?? false\"\n [openOnFocus]=\"lookup.autocompleteAutoClear ?? true\"\n [inlineSearch]=\"lookup.autocompleteInlineSearch ?? false\"\n [placeholder]=\"placeholder\"\n [className]=\"lookup.className\"\n [dropdownClassName]=\"lookup.dropdownClassName\"\n [disabled]=\"isInputDisabled()\"\n (valueChange)=\"autocompleteFilter($event)\"\n [searchTrim]=\"config().descriptor.trimOption\"\n [templates]=\"showFilterIcon() ? [autocompletePrependIcon] : []\">\n </mng-autocomplete>\n }\n @case (lookupTypeDropdown) {\n <mng-dropdown\n *mngRerender=\"isMultiselect()\"\n [ngModel]=\"filter.state()?.displayValue\"\n [dataProvider]=\"lookup.dataProvider\"\n [optionsValueProperty]=\"lookup.optionsValueProperty\"\n [optionsLabelProperty]=\"lookup.optionsLabelProperty\"\n [optionsLabelTranslate]=\"lookup.optionsLabelTranslate\"\n [multiselect]=\"isMultiselect()\"\n [placeholder]=\"placeholder\"\n [className]=\"lookup.className\"\n [dropdownClassName]=\"lookup.dropdownClassName\"\n [showClear]=\"false\"\n [changeValueOnBlur]=\"isMultiselect()\"\n [disabled]=\"isInputDisabled()\"\n (valueChange)=\"dropdownFilter($event)\"\n [templates]=\"showFilterIcon() ? [dropdownPrependIcon] : []\">\n </mng-dropdown>\n }\n }\n }\n </ng-template>\n\n <ng-template mngAutocompleteTemplate name=\"prepend\" #autocompletePrependIcon=\"mngAutocompleteTemplate\">\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </ng-template>\n <ng-template mngDropdownTemplate name=\"prepend\" #dropdownPrependIcon=\"mngDropdownTemplate\">\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </ng-template>\n <ng-template mngDateRangeTemplate name=\"prepend\" #dateRangePrependIcon=\"mngDateRangeTemplate\">\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </ng-template>\n <ng-template mngNumberRangeTemplate name=\"prepend\" #numberRangePrependIcon=\"mngNumberRangeTemplate\">\n <ng-container *ngTemplateOutlet=\"iconTemplate\"></ng-container>\n </ng-template>\n\n <ng-template #iconTemplate>\n <button\n #icon\n class=\"mng-filter-options mng-filter-icon cursor-pointer pi pi-filter w-full h-full rounded-tl-md rounded-bl-md\"\n (click)=\"toggleMenu($event)\"\n (keydown)=\"onToggleButtonKeyDown($event)\"></button>\n </ng-template>\n\n @if (overlayVisible()) {\n <div\n class=\"p-datatable-filter-overlay\"\n (click)=\"onContentClick()\"\n [@overlayAnimation]=\"'visible'\"\n (@overlayAnimation.start)=\"onOverlayAnimationStart($event)\"\n (@overlayAnimation.done)=\"onOverlayAnimationEnd($event)\"\n (keydown.escape)=\"onEscape()\">\n <ul class=\"p-datatable-filter-constraint-list\">\n @for (matchMode of matchModes(); track matchMode; let i = $index) {\n <li\n class=\"p-datatable-filter-constraint\"\n [class.p-datatable-filter-constraint-selected]=\"matchMode.value === filter.state()?.displayMatchMode\"\n (click)=\"onMatchModeChange(matchMode.value)\"\n (keydown)=\"onMatchModeKeyDown($event)\"\n (keydown.enter)=\"this.onMatchModeChange(matchMode.value)\"\n [attr.tabindex]=\"i === 0 ? '0' : null\">\n {{ matchMode.label }}\n </li>\n }\n @if (config().descriptor.filterType === FilterTypeEnum.String) {\n <li class=\"p-datatable-filter-constraint-separator\" (keydown)=\"onMatchModeKeyDown($event)\"></li>\n <li\n class=\"p-datatable-filter-constraint\"\n (click)=\"onCaseSensitivityToggle()\"\n (keydown)=\"onMatchModeKeyDown($event)\"\n (keydown.enter)=\"onCaseSensitivityToggle()\">\n <div class=\"flex items-center\">\n <span class=\"mr-2\"> {{ 'mngFilter.caseSensitive' | translate }} </span>\n <p-toggle-switch [ngModel]=\"filter.state()?.caseSensitive || false\" class=\"ml-auto pointer-events-none\"></p-toggle-switch>\n </div>\n </li>\n }\n <li class=\"p-datatable-filter-constraint-separator\" (keydown)=\"onMatchModeKeyDown($event)\"></li>\n <li class=\"p-datatable-filter-constraint\" (click)=\"clear()\" (keydown)=\"onMatchModeKeyDown($event)\" (keydown.enter)=\"clear()\">\n {{ 'mngPrime.noFilter' | translate }}\n </li>\n </ul>\n </div>\n }\n </div>\n\n @if (!showFilterIcon()) {\n <button\n #icon\n class=\"mng-filter-options cursor-pointer ml-1\"\n [ngClass]=\"{\n 'text-primary': filter.isActive(),\n 'text-slate-400': !filter.isActive()\n }\"\n (click)=\"toggleMenu($event)\"\n (keydown)=\"onToggleButtonKeyDown($event)\">\n <i class=\"pi pi-ellipsis-v\"></i>\n </button>\n }\n</div>\n", styles: ["mng-table-filter{--filter-active-bg: var(--color-primary-50);--filter-active-color: var(--color-primary-600)}mng-table-filter .mng-filter-string{min-width:135px}mng-table-filter .mng-filter-number{min-width:165px}mng-table-filter .mng-filter-date{min-width:170px}mng-table-filter .mng-filter-boolean{min-width:80px}mng-table-filter .mng-filter-lookup,mng-table-filter .mng-filter-lookupenum{min-width:180px}mng-table-filter .mng-filter-required{position:relative}mng-table-filter p-tag.mng-filter-required{border:1px solid var(--color-red-500)}mng-table-filter .mng-filter-required:after{content:\"\";position:absolute;top:0;right:0;width:1rem;height:1rem;background-color:var(--color-red-500);z-index:1;clip-path:polygon(0 0,100% 0,100% 100%,0 0);border-top-right-radius:var(--p-inputgroup-addon-border-radius)}mng-table-filter .mng-filter-icon{color:var(--p-inputgroup-addon-color)}mng-table-filter .mng-filter-icon:hover{background:var(--p-select-filled-hover-background)}mng-table-filter .mng-filter-active *{border-color:var(--filter-active-color)!important}mng-table-filter .mng-filter-active p-inputgroup-addon,mng-table-filter .mng-filter-active input,mng-table-filter .mng-filter-active p-select,mng-table-filter .mng-filter-active p-multiselect,mng-table-filter .mng-filter-active .p-autocomplete-input-multiple{background:var(--filter-active-bg)}mng-table-filter .mng-filter-active .mng-filter-icon{color:var(--filter-active-color)}:root[class*=app-dark] mng-table-filter{--filter-active-bg: var(--p-surface-800);--filter-active-color: var(--p-surface-400)}\n"] }]
|
|
827
|
+
}], ctorParameters: () => [], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: true }] }], model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], showFilterIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilterIcon", required: false }] }], showTitleAsPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTitleAsPlaceholder", required: false }] }], icon: [{ type: i0.ViewChild, args: ['icon', { isSignal: true }] }] } });
|
|
828
|
+
|
|
829
|
+
var filter_component = /*#__PURE__*/Object.freeze({
|
|
830
|
+
__proto__: null,
|
|
831
|
+
TableFilterComponent: TableFilterComponent
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
class TableColumnValueComponent {
|
|
835
|
+
constructor() {
|
|
836
|
+
this.columnDisplayTypeString = ColumnDisplayTypeEnum.String;
|
|
837
|
+
this.columnDisplayTypeNumber = ColumnDisplayTypeEnum.Number;
|
|
838
|
+
this.columnDisplayTypeCurrency = ColumnDisplayTypeEnum.Currency;
|
|
839
|
+
this.columnDisplayTypeBoolean = ColumnDisplayTypeEnum.Boolean;
|
|
840
|
+
this.columnDisplayTypeDate = ColumnDisplayTypeEnum.Date;
|
|
841
|
+
this.columnDisplayTypeEnum = ColumnDisplayTypeEnum.Enum;
|
|
842
|
+
this.columnDisplayTypeComponent = ColumnDisplayTypeEnum.Component;
|
|
843
|
+
this.columnDisplayTypeHtml = ColumnDisplayTypeEnum.Html;
|
|
844
|
+
this.elementRef = inject(ElementRef);
|
|
845
|
+
this.messageService = inject(MessageService);
|
|
846
|
+
this.translate = inject(TranslateService);
|
|
847
|
+
this.getterPipe = new GetterPipe();
|
|
848
|
+
this.templatePipe = new TemplatePipe();
|
|
849
|
+
this.jsonPathPipe = new JsonPathPipe();
|
|
850
|
+
this.descriptor = input.required(...(ngDevMode ? [{ debugName: "descriptor" }] : []));
|
|
851
|
+
this.item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
|
|
852
|
+
this.styleMaxWidth = computed(() => this.descriptor().maxWidth ?? null, ...(ngDevMode ? [{ debugName: "styleMaxWidth" }] : []));
|
|
853
|
+
this.className = computed(() => {
|
|
854
|
+
let className = 'nowrap';
|
|
855
|
+
if (this.descriptor().columnDisplayType === ColumnDisplayTypeEnum.String && this.descriptor().isMultiline) {
|
|
856
|
+
className += ' multiline';
|
|
857
|
+
}
|
|
858
|
+
return className;
|
|
859
|
+
}, ...(ngDevMode ? [{ debugName: "className" }] : []));
|
|
860
|
+
this.value = computed(() => {
|
|
861
|
+
let value = this.jsonPathPipe.transform(this.item(), `$.${this.descriptor().property}`);
|
|
862
|
+
if (typeof this.descriptor().getter === 'function') {
|
|
863
|
+
value = this.getterPipe.transform(value, this.descriptor().getter, this.item());
|
|
864
|
+
}
|
|
865
|
+
if (this.descriptor().template) {
|
|
866
|
+
value = this.templatePipe.transform(value, this.descriptor().template);
|
|
867
|
+
}
|
|
868
|
+
return value;
|
|
869
|
+
}, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
870
|
+
this.currency = computed(() => {
|
|
871
|
+
if (this.descriptor().columnDisplayType === ColumnDisplayTypeEnum.Currency) {
|
|
872
|
+
return this.descriptor().currencyProperty ? this.item()[this.descriptor().currencyProperty] : (this.descriptor().currencyCode ?? 'EUR');
|
|
873
|
+
}
|
|
874
|
+
return;
|
|
875
|
+
}, ...(ngDevMode ? [{ debugName: "currency" }] : []));
|
|
876
|
+
this.hasCopyToClipboard = computed(() => this.descriptor().hasCopyToClipboard && this.value() != null, ...(ngDevMode ? [{ debugName: "hasCopyToClipboard" }] : []));
|
|
877
|
+
this.componentInputs = computed(() => {
|
|
878
|
+
const inputs = {
|
|
879
|
+
value: this.value(),
|
|
880
|
+
item: this.item(),
|
|
881
|
+
descriptor: this.descriptor()
|
|
882
|
+
};
|
|
883
|
+
if (this.descriptor().customComponentInputs) {
|
|
884
|
+
return { ...inputs, ...this.descriptor().customComponentInputs };
|
|
885
|
+
}
|
|
886
|
+
return inputs;
|
|
887
|
+
}, ...(ngDevMode ? [{ debugName: "componentInputs" }] : []));
|
|
888
|
+
}
|
|
889
|
+
copyToClipboard(event) {
|
|
890
|
+
event.stopPropagation();
|
|
891
|
+
let value = this.elementRef.nativeElement.innerText.trim();
|
|
892
|
+
const clipboardValueGetter = this.descriptor().clipboardValueGetter;
|
|
893
|
+
if (clipboardValueGetter) {
|
|
894
|
+
value = clipboardValueGetter(this.value(), this.item());
|
|
895
|
+
}
|
|
896
|
+
navigator.clipboard.writeText(value);
|
|
897
|
+
const title = this.translate.instant('mngTable.copyNotificationTitle');
|
|
898
|
+
const message = this.translate.instant('mngTable.copyNotificationMessage', { value });
|
|
899
|
+
this.messageService.add({ severity: 'info', summary: title, detail: message });
|
|
900
|
+
}
|
|
901
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnValueComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
902
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableColumnValueComponent, isStandalone: true, selector: "mng-table-column-value", inputs: { descriptor: { classPropertyName: "descriptor", publicName: "descriptor", isSignal: true, isRequired: true, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "class": "className()", "style.max-width.px": "styleMaxWidth()" } }, ngImport: i0, template: "@if (descriptor().localizationExistsProperty && !item()[descriptor().localizationExistsProperty!]) {\n <i class=\"pi pi-exclamation-circle\" [pTooltip]=\"'mngTable.translationMissing' | translate\"></i>\n}\n@switch (descriptor().columnDisplayType) {\n @case (columnDisplayTypeString) {\n @if (descriptor().hasValueAsTooltip) {\n <span [pTooltip]=\"value()\" tooltipPosition=\"left\">{{ value() }}</span>\n } @else {\n {{ value() }}\n }\n }\n @case (columnDisplayTypeHtml) {\n <span [innerHTML]=\"value()\"></span>\n }\n @case (columnDisplayTypeNumber) {\n {{ value() | number: descriptor().displayFormat : descriptor().locale }}\n }\n @case (columnDisplayTypeCurrency) {\n {{ value() | currency: currency() : descriptor().currencyDisplay : descriptor().displayFormat : descriptor().locale }}\n }\n @case (columnDisplayTypeDate) {\n {{ value() | date: descriptor().displayFormat }}\n }\n @case (columnDisplayTypeBoolean) {\n @if (descriptor().booleanAsIcon) {\n <i [class]=\"value() | mngBoolean: descriptor().booleanYes : descriptor().booleanNo : true\"></i>\n } @else {\n {{ value() | mngBoolean: descriptor().booleanYes : descriptor().booleanNo | translate }}\n }\n }\n @case (columnDisplayTypeEnum) {\n {{ value() | mngEnum: descriptor().enum | translate }}\n }\n @case (columnDisplayTypeComponent) {\n <ng-container [mngComponent]=\"descriptor().customComponentType!\" [inputs]=\"componentInputs()\"></ng-container>\n }\n}\n@if (hasCopyToClipboard()) {\n <div class=\"help-buttons\">\n <button pButton type=\"button\" icon=\"pi pi-copy\" class=\"p-button-rounded p-button-info p-button-sm\" (click)=\"copyToClipboard($event)\"></button>\n </div>\n}\n", styles: [":host{display:inline-block;overflow:hidden}:host.nowrap{white-space:nowrap;text-overflow:ellipsis}:host.multiline{white-space:pre-wrap;word-wrap:break-word}.help-buttons{display:none;position:absolute;right:0;top:50%;transform:translateY(-50%)}.help-buttons .p-button{height:1.9rem;width:1.9rem;padding:0}\n"], dependencies: [{ kind: "directive", type: ComponentDirective, selector: "[mngComponent]", inputs: ["mngComponent", "injectionToken", "inputs", "attachToHost", "parentInjector"], outputs: ["instanceCreated"] }, { kind: "directive", type: ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: BooleanPipe, name: "mngBoolean" }, { kind: "pipe", type: EnumPipe, name: "mngEnum" }, { kind: "pipe", type: DecimalPipe, name: "number" }, { kind: "pipe", type: CurrencyPipe, name: "currency" }, { kind: "pipe", type: DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
903
|
+
}
|
|
904
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableColumnValueComponent, decorators: [{
|
|
905
|
+
type: Component,
|
|
906
|
+
args: [{ selector: 'mng-table-column-value', imports: [TranslatePipe, BooleanPipe, EnumPipe, ComponentDirective, DecimalPipe, CurrencyPipe, DatePipe, ButtonDirective, Tooltip], changeDetection: ChangeDetectionStrategy.OnPush, host: { '[class]': 'className()', '[style.max-width.px]': 'styleMaxWidth()' }, template: "@if (descriptor().localizationExistsProperty && !item()[descriptor().localizationExistsProperty!]) {\n <i class=\"pi pi-exclamation-circle\" [pTooltip]=\"'mngTable.translationMissing' | translate\"></i>\n}\n@switch (descriptor().columnDisplayType) {\n @case (columnDisplayTypeString) {\n @if (descriptor().hasValueAsTooltip) {\n <span [pTooltip]=\"value()\" tooltipPosition=\"left\">{{ value() }}</span>\n } @else {\n {{ value() }}\n }\n }\n @case (columnDisplayTypeHtml) {\n <span [innerHTML]=\"value()\"></span>\n }\n @case (columnDisplayTypeNumber) {\n {{ value() | number: descriptor().displayFormat : descriptor().locale }}\n }\n @case (columnDisplayTypeCurrency) {\n {{ value() | currency: currency() : descriptor().currencyDisplay : descriptor().displayFormat : descriptor().locale }}\n }\n @case (columnDisplayTypeDate) {\n {{ value() | date: descriptor().displayFormat }}\n }\n @case (columnDisplayTypeBoolean) {\n @if (descriptor().booleanAsIcon) {\n <i [class]=\"value() | mngBoolean: descriptor().booleanYes : descriptor().booleanNo : true\"></i>\n } @else {\n {{ value() | mngBoolean: descriptor().booleanYes : descriptor().booleanNo | translate }}\n }\n }\n @case (columnDisplayTypeEnum) {\n {{ value() | mngEnum: descriptor().enum | translate }}\n }\n @case (columnDisplayTypeComponent) {\n <ng-container [mngComponent]=\"descriptor().customComponentType!\" [inputs]=\"componentInputs()\"></ng-container>\n }\n}\n@if (hasCopyToClipboard()) {\n <div class=\"help-buttons\">\n <button pButton type=\"button\" icon=\"pi pi-copy\" class=\"p-button-rounded p-button-info p-button-sm\" (click)=\"copyToClipboard($event)\"></button>\n </div>\n}\n", styles: [":host{display:inline-block;overflow:hidden}:host.nowrap{white-space:nowrap;text-overflow:ellipsis}:host.multiline{white-space:pre-wrap;word-wrap:break-word}.help-buttons{display:none;position:absolute;right:0;top:50%;transform:translateY(-50%)}.help-buttons .p-button{height:1.9rem;width:1.9rem;padding:0}\n"] }]
|
|
907
|
+
}], propDecorators: { descriptor: [{ type: i0.Input, args: [{ isSignal: true, alias: "descriptor", required: true }] }], item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }] } });
|
|
908
|
+
|
|
909
|
+
class FilterValuePipe {
|
|
910
|
+
constructor() {
|
|
911
|
+
this.locale = inject(LOCALE_ID);
|
|
912
|
+
this.translate = inject(TranslateService);
|
|
913
|
+
this.enumPipe = new EnumPipe();
|
|
914
|
+
this.subject = new ReplaySubject(1);
|
|
915
|
+
}
|
|
916
|
+
transform(value, descriptor) {
|
|
917
|
+
const valTransform = this.prepareValueTransform(value, descriptor);
|
|
918
|
+
this.subscription?.unsubscribe();
|
|
919
|
+
if (valTransform.translate && valTransform.valueArr.length > 0) {
|
|
920
|
+
this.subscription = this.translate.stream(valTransform.valueArr).subscribe((i18n) => {
|
|
921
|
+
this.subject.next(valTransform.valueArr.map(k => i18n[k]).join(', '));
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
else {
|
|
925
|
+
this.subject.next(valTransform.valueArr.join(', '));
|
|
926
|
+
}
|
|
927
|
+
return this.subject.asObservable();
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* If returns a string, this represents i18n key that must go through translation. If translation is not needed, undefined is returned.
|
|
931
|
+
*/
|
|
932
|
+
prepareValueTransform(value, descriptor) {
|
|
933
|
+
const result = {
|
|
934
|
+
translate: false,
|
|
935
|
+
valueArr: Array.isArray(value) ? value : [value]
|
|
936
|
+
};
|
|
937
|
+
if (value == null) {
|
|
938
|
+
result.valueArr = [];
|
|
939
|
+
}
|
|
940
|
+
switch (descriptor?.filterType) {
|
|
941
|
+
case FilterTypeEnum.Date:
|
|
942
|
+
// eslint-disable-next-line no-case-declarations
|
|
943
|
+
const datePipe = new DatePipe(this.locale);
|
|
944
|
+
result.valueArr = result.valueArr.map(v => datePipe.transform(v, descriptor.displayFormat, descriptor.locale));
|
|
945
|
+
break;
|
|
946
|
+
case FilterTypeEnum.Number:
|
|
947
|
+
// eslint-disable-next-line no-case-declarations
|
|
948
|
+
const decimalPipe = new DecimalPipe(this.locale);
|
|
949
|
+
result.valueArr = result.valueArr.map(v => decimalPipe.transform(v, descriptor.displayFormat, descriptor.locale));
|
|
950
|
+
break;
|
|
951
|
+
case FilterTypeEnum.Boolean:
|
|
952
|
+
// eslint-disable-next-line no-case-declarations
|
|
953
|
+
const booleanPipe = new BooleanPipe();
|
|
954
|
+
result.valueArr = result.valueArr.map(v => booleanPipe.transform(v));
|
|
955
|
+
result.translate = true;
|
|
956
|
+
break;
|
|
957
|
+
case FilterTypeEnum.LookupEnum:
|
|
958
|
+
// eslint-disable-next-line no-case-declarations
|
|
959
|
+
const enumPipe = new EnumPipe();
|
|
960
|
+
result.valueArr = result.valueArr.map(v => enumPipe.transform(v, descriptor.enum));
|
|
961
|
+
result.translate = true;
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
return result;
|
|
965
|
+
}
|
|
966
|
+
ngOnDestroy() {
|
|
967
|
+
this.subscription?.unsubscribe();
|
|
968
|
+
this.subject.complete();
|
|
969
|
+
}
|
|
970
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
971
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: FilterValuePipe, isStandalone: true, name: "mngFilterValue" }); }
|
|
972
|
+
}
|
|
973
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FilterValuePipe, decorators: [{
|
|
974
|
+
type: Pipe,
|
|
975
|
+
args: [{
|
|
976
|
+
name: 'mngFilterValue',
|
|
977
|
+
pure: true
|
|
978
|
+
}]
|
|
979
|
+
}] });
|
|
980
|
+
|
|
981
|
+
class TableFilterActiveTagComponent {
|
|
982
|
+
constructor() {
|
|
983
|
+
this.translateService = inject(TranslateService);
|
|
984
|
+
this.FilterMatchMode = FilterMatchMode;
|
|
985
|
+
this.model = input.required(...(ngDevMode ? [{ debugName: "model" }] : []));
|
|
986
|
+
this.filter = input.required(...(ngDevMode ? [{ debugName: "filter" }] : []));
|
|
987
|
+
this.edit = output();
|
|
988
|
+
this.remove = output();
|
|
989
|
+
this.toggleDisabled = output();
|
|
990
|
+
this.label = computed(() => this.getPropertyLabelKey(this.filter().config.descriptor), ...(ngDevMode ? [{ debugName: "label" }] : []));
|
|
991
|
+
this.matchMode = computed(() => this.filter().displayMatchMode, ...(ngDevMode ? [{ debugName: "matchMode" }] : []));
|
|
992
|
+
this.matchModeSymbol = computed(() => `mngFilterActiveTag.matchMode.${this.matchMode()}`, ...(ngDevMode ? [{ debugName: "matchModeSymbol" }] : []));
|
|
993
|
+
this.value = computed(() => this.filter().displayValue, ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
994
|
+
this.isActive = computed(() => this.filter()?.matchMode === FilterMatchMode.Exists || this.filter()?.matchMode === FilterMatchMode.DoesNotExist || !isFilterValueBlank(this.value()), ...(ngDevMode ? [{ debugName: "isActive" }] : []));
|
|
995
|
+
this.menuItems = signal([], ...(ngDevMode ? [{ debugName: "menuItems" }] : []));
|
|
996
|
+
this.tagMenu = viewChild.required(Menu);
|
|
997
|
+
}
|
|
998
|
+
onRemove(event) {
|
|
999
|
+
event.stopPropagation();
|
|
1000
|
+
this.remove.emit({
|
|
1001
|
+
filter: this.filter(),
|
|
1002
|
+
event: event
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
onEdit(event) {
|
|
1006
|
+
this.edit.emit({
|
|
1007
|
+
filter: this.filter(),
|
|
1008
|
+
event: event
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
onDisable(event) {
|
|
1012
|
+
this.filter().disabled = !this.filter().disabled;
|
|
1013
|
+
this.toggleDisabled.emit({
|
|
1014
|
+
filter: this.filter(),
|
|
1015
|
+
event: event
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
openTagMenu(event) {
|
|
1019
|
+
this.menuItems.set([
|
|
1020
|
+
{
|
|
1021
|
+
label: this.translateService.instant('mngFilterActiveTag.edit'),
|
|
1022
|
+
icon: 'pi pi-pencil',
|
|
1023
|
+
command: () => {
|
|
1024
|
+
// close the menu first
|
|
1025
|
+
this.tagMenu().hide();
|
|
1026
|
+
// open edit second
|
|
1027
|
+
setTimeout(() => this.onEdit(event), 0);
|
|
1028
|
+
}
|
|
1029
|
+
},
|
|
1030
|
+
{ separator: true },
|
|
1031
|
+
{
|
|
1032
|
+
label: this.filter().disabled ? this.translateService.instant('mngFilterActiveTag.enable') : this.translateService.instant('mngFilterActiveTag.disable'),
|
|
1033
|
+
icon: this.filter().disabled ? 'pi pi-check-circle' : 'pi pi-ban',
|
|
1034
|
+
command: () => {
|
|
1035
|
+
this.onDisable(event);
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
{ separator: true },
|
|
1039
|
+
{ label: this.translateService.instant('mngFilterActiveTag.remove'), icon: 'pi pi-times', command: () => this.onRemove(event) }
|
|
1040
|
+
]);
|
|
1041
|
+
this.tagMenu().toggle(event);
|
|
1042
|
+
}
|
|
1043
|
+
getPropertyLabelKey(filterDescriptor) {
|
|
1044
|
+
if (filterDescriptor.isGenericFilter) {
|
|
1045
|
+
return filterDescriptor.property;
|
|
1046
|
+
}
|
|
1047
|
+
let labelKey;
|
|
1048
|
+
if (filterDescriptor.title !== undefined && !filterDescriptor.titleUseModelBase) {
|
|
1049
|
+
labelKey = filterDescriptor.title;
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
labelKey = getI18nTypePropertyKey(this.model().i18nBaseKey, filterDescriptor.title ?? filterDescriptor.property);
|
|
1053
|
+
}
|
|
1054
|
+
return labelKey;
|
|
1055
|
+
}
|
|
1056
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterActiveTagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1057
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableFilterActiveTagComponent, isStandalone: true, selector: "mng-table-filter-active-tag", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { edit: "edit", remove: "remove", toggleDisabled: "toggleDisabled" }, viewQueries: [{ propertyName: "tagMenu", first: true, predicate: Menu, descendants: true, isSignal: true }], ngImport: i0, template: "<p-tag\n [class.opacity-70]=\"filter().disabled\"\n severity=\"secondary\"\n styleClass=\"mr-1 mng-tag-outlined\"\n [class.mng-filter-required]=\"!isActive() && filter().config.descriptor.isRequired\">\n <div class=\"flex relative items-center gap-2 p-1 cursor-pointer\" (click)=\"openTagMenu($event)\">\n <span>{{ label() | translate }}</span>\n @if (matchMode() === FilterMatchMode.Between) {\n <span class=\"font-semibold\">{{ value()?.[0] | mngFilterValue: filter().config.descriptor | async }}</span>\n <span class=\"text-primary\">{{ matchModeSymbol() | translate }}</span>\n <span class=\"font-semibold\">{{ value()?.[1] | mngFilterValue: filter().config.descriptor | async }}</span>\n } @else {\n <span class=\"text-primary\">{{ matchModeSymbol() | translate }}</span>\n <span class=\"font-semibold\">{{ value() | mngFilterValue: filter().config.descriptor | async }}</span>\n @if (filter().caseSensitive) {\n <small class=\"border-solid border rounded px-1 text-primary-400\">Aa</small>\n }\n }\n <p-divider layout=\"vertical\" class=\"!p-0 !mx-[3px]\" />\n\n @if (isActive()) {\n <span class=\"pi pi-times text-xs\" (click)=\"onRemove($event)\"></span>\n }\n\n @if (filter().disabled) {\n <p-divider layout=\"horizontal\" class=\"!absolute left-0 !m-0 border-t opacity-50\"></p-divider>\n }\n </div>\n</p-tag>\n<p-menu [popup]=\"true\" [model]=\"menuItems()\" appendTo=\"body\"></p-menu>\n", styles: ["mng-table-filter-active-tag.p-tag.p-tag-secondary.mng-tag-outlined{background-color:unset;border:1px solid var(--mng-tag-secondary-outlined-border)}\n"], dependencies: [{ kind: "component", type: Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex", "appendTo"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "component", type: Divider, selector: "p-divider", inputs: ["styleClass", "layout", "type", "align"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: FilterValuePipe, name: "mngFilterValue" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1058
|
+
}
|
|
1059
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterActiveTagComponent, decorators: [{
|
|
1060
|
+
type: Component,
|
|
1061
|
+
args: [{ selector: 'mng-table-filter-active-tag', imports: [TranslatePipe, FilterValuePipe, AsyncPipe, Tag, Menu, Divider], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<p-tag\n [class.opacity-70]=\"filter().disabled\"\n severity=\"secondary\"\n styleClass=\"mr-1 mng-tag-outlined\"\n [class.mng-filter-required]=\"!isActive() && filter().config.descriptor.isRequired\">\n <div class=\"flex relative items-center gap-2 p-1 cursor-pointer\" (click)=\"openTagMenu($event)\">\n <span>{{ label() | translate }}</span>\n @if (matchMode() === FilterMatchMode.Between) {\n <span class=\"font-semibold\">{{ value()?.[0] | mngFilterValue: filter().config.descriptor | async }}</span>\n <span class=\"text-primary\">{{ matchModeSymbol() | translate }}</span>\n <span class=\"font-semibold\">{{ value()?.[1] | mngFilterValue: filter().config.descriptor | async }}</span>\n } @else {\n <span class=\"text-primary\">{{ matchModeSymbol() | translate }}</span>\n <span class=\"font-semibold\">{{ value() | mngFilterValue: filter().config.descriptor | async }}</span>\n @if (filter().caseSensitive) {\n <small class=\"border-solid border rounded px-1 text-primary-400\">Aa</small>\n }\n }\n <p-divider layout=\"vertical\" class=\"!p-0 !mx-[3px]\" />\n\n @if (isActive()) {\n <span class=\"pi pi-times text-xs\" (click)=\"onRemove($event)\"></span>\n }\n\n @if (filter().disabled) {\n <p-divider layout=\"horizontal\" class=\"!absolute left-0 !m-0 border-t opacity-50\"></p-divider>\n }\n </div>\n</p-tag>\n<p-menu [popup]=\"true\" [model]=\"menuItems()\" appendTo=\"body\"></p-menu>\n", styles: ["mng-table-filter-active-tag.p-tag.p-tag-secondary.mng-tag-outlined{background-color:unset;border:1px solid var(--mng-tag-secondary-outlined-border)}\n"] }]
|
|
1062
|
+
}], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: true }] }], edit: [{ type: i0.Output, args: ["edit"] }], remove: [{ type: i0.Output, args: ["remove"] }], toggleDisabled: [{ type: i0.Output, args: ["toggleDisabled"] }], tagMenu: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Menu), { isSignal: true }] }] } });
|
|
1063
|
+
|
|
1064
|
+
var filterActiveTag_component = /*#__PURE__*/Object.freeze({
|
|
1065
|
+
__proto__: null,
|
|
1066
|
+
TableFilterActiveTagComponent: TableFilterActiveTagComponent
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
const VALUE_ACCESSOR = {
|
|
1070
|
+
provide: NG_VALUE_ACCESSOR,
|
|
1071
|
+
useExisting: forwardRef(() => TableFilterFormMultiselectComponent),
|
|
1072
|
+
multi: true
|
|
1073
|
+
};
|
|
1074
|
+
class TableFilterFormMultiselectComponent {
|
|
1075
|
+
constructor() {
|
|
1076
|
+
this.String = String;
|
|
1077
|
+
this.FilterTypeEnum = FilterTypeEnum;
|
|
1078
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
1079
|
+
this.onChangeFn = () => { };
|
|
1080
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
1081
|
+
this.onTouchedFn = () => { };
|
|
1082
|
+
this.filterType = input(...(ngDevMode ? [undefined, { debugName: "filterType" }] : []));
|
|
1083
|
+
this.enableCaseSensitive = input(false, ...(ngDevMode ? [{ debugName: "enableCaseSensitive", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
1084
|
+
this.caseSensitiveModel = model(...(ngDevMode ? [undefined, { debugName: "caseSensitiveModel" }] : []));
|
|
1085
|
+
this.inputTrim = input(...(ngDevMode ? [undefined, { debugName: "inputTrim" }] : []));
|
|
1086
|
+
this.disabledInput = input(false, ...(ngDevMode ? [{ debugName: "disabledInput", alias: 'disabled', transform: booleanAttribute }] : [{ alias: 'disabled', transform: booleanAttribute }]));
|
|
1087
|
+
this._disabled = signal(false, ...(ngDevMode ? [{ debugName: "_disabled" }] : []));
|
|
1088
|
+
this.disabled = computed(() => this.disabledInput() || this._disabled(), ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
1089
|
+
this.value = signal([], ...(ngDevMode ? [{ debugName: "value" }] : []));
|
|
1090
|
+
this.stringValues = computed(() => this.value().map(v => String(v)), ...(ngDevMode ? [{ debugName: "stringValues" }] : []));
|
|
1091
|
+
}
|
|
1092
|
+
registerOnChange(fn) {
|
|
1093
|
+
this.onChangeFn = fn;
|
|
1094
|
+
}
|
|
1095
|
+
registerOnTouched(fn) {
|
|
1096
|
+
this.onTouchedFn = fn;
|
|
1097
|
+
}
|
|
1098
|
+
setDisabledState(isDisabled) {
|
|
1099
|
+
this._disabled.set(isDisabled);
|
|
1100
|
+
}
|
|
1101
|
+
onBlur() {
|
|
1102
|
+
this.onTouchedFn();
|
|
1103
|
+
}
|
|
1104
|
+
writeValue(obj) {
|
|
1105
|
+
if (obj === undefined || obj === null || !Array.isArray(obj)) {
|
|
1106
|
+
this.value.set([]);
|
|
1107
|
+
}
|
|
1108
|
+
else {
|
|
1109
|
+
this.value.set(obj);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
onValueNumberChange(event) {
|
|
1113
|
+
const el = event?.target;
|
|
1114
|
+
const rawValue = el?.value;
|
|
1115
|
+
const value = Number(rawValue);
|
|
1116
|
+
const values = Array.isArray(this.value()) ? [...this.value()] : [];
|
|
1117
|
+
if (rawValue && !Number.isNaN(value) && !values.includes(value))
|
|
1118
|
+
values.push(value);
|
|
1119
|
+
this.value.set(values);
|
|
1120
|
+
if (el)
|
|
1121
|
+
el.value = '';
|
|
1122
|
+
this.onChangeFn(this.value());
|
|
1123
|
+
}
|
|
1124
|
+
onValueChange(event) {
|
|
1125
|
+
const el = event?.target;
|
|
1126
|
+
const inputValue = el?.value ?? '';
|
|
1127
|
+
const splitValues = this.splitValues(inputValue);
|
|
1128
|
+
const values = Array.isArray(this.value()) ? [...this.value()] : [];
|
|
1129
|
+
for (const val of splitValues) {
|
|
1130
|
+
if (val && !values.includes(val))
|
|
1131
|
+
values.push(val);
|
|
1132
|
+
}
|
|
1133
|
+
this.value.set(values);
|
|
1134
|
+
if (el)
|
|
1135
|
+
el.value = '';
|
|
1136
|
+
this.onChangeFn(this.value());
|
|
1137
|
+
}
|
|
1138
|
+
splitValues(value) {
|
|
1139
|
+
// split on comma, semicolon, newline, or tab
|
|
1140
|
+
return value.split(/[\n,;\t]/g).filter(x => x.length > 0);
|
|
1141
|
+
}
|
|
1142
|
+
removeValue(index) {
|
|
1143
|
+
const values = [...(this.value() || [])];
|
|
1144
|
+
values.splice(index, 1);
|
|
1145
|
+
this.value.set(values);
|
|
1146
|
+
this.onChangeFn(this.value());
|
|
1147
|
+
}
|
|
1148
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterFormMultiselectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1149
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableFilterFormMultiselectComponent, isStandalone: true, selector: "mng-table-filter-form-multiselect", inputs: { filterType: { classPropertyName: "filterType", publicName: "filterType", isSignal: true, isRequired: false, transformFunction: null }, enableCaseSensitive: { classPropertyName: "enableCaseSensitive", publicName: "enableCaseSensitive", isSignal: true, isRequired: false, transformFunction: null }, caseSensitiveModel: { classPropertyName: "caseSensitiveModel", publicName: "caseSensitiveModel", isSignal: true, isRequired: false, transformFunction: null }, inputTrim: { classPropertyName: "inputTrim", publicName: "inputTrim", isSignal: true, isRequired: false, transformFunction: null }, disabledInput: { classPropertyName: "disabledInput", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { caseSensitiveModel: "caseSensitiveModelChange" }, providers: [VALUE_ACCESSOR], ngImport: i0, template: "<p-inputgroup>\n <p-multiSelect\n [ngModel]=\"value()\"\n (ngModelChange)=\"value.set($event)\"\n [options]=\"value()\"\n [showToggleAll]=\"false\"\n [filter]=\"false\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [maxSelectedLabels]=\"1\"\n [selectedItemsLabel]=\"'mngDropdown.multiselectOverMaxDisplayLimit' | translate\"\n [selectAll]=\"false\"\n [disabled]=\"disabled()\"\n display=\"chip\"\n appendTo=\"body\"\n required=\"true\"\n panelStyleClass=\"table-filter-form-multiselect-panel p-2 flex flex-col gap-2 w-full max-w-72\">\n <ng-template pTemplate=\"header\">\n @if (filterType() === FilterTypeEnum.String) {\n <input\n type=\"text\"\n pInputText\n class=\"mng-filter-string w-full\"\n [disabled]=\"disabled()\"\n (keydown.enter)=\"onValueChange($event); $event.preventDefault()\"\n (keydown.tab)=\"onValueChange($event)\"\n (blur)=\"onValueChange($event)\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [mngInputTrim]=\"inputTrim()\" />\n } @else {\n <p-inputNumber\n inputStyleClass=\"mng-filter-number\"\n [disabled]=\"disabled()\"\n (keydown.enter)=\"onValueNumberChange($event); $event.preventDefault()\"\n (keydown.tab)=\"onValueNumberChange($event)\"\n (onBlur)=\"onValueNumberChange($event)\"\n [placeholder]=\"'mngFilter.value' | translate\"\n useGrouping=\"false\"\n required=\"true\" />\n }\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <div class=\"flex flex-wrap gap-1 overflow-auto\">\n @if (value().length) {\n @for (val of stringValues(); track val; let i = $index) {\n <p-chip [label]=\"val\" removable (onRemove)=\"removeValue(i)\" />\n }\n } @else {\n <span class=\"p-1\">{{ 'mngFilter.noValues' | translate }}</span>\n }\n </div>\n </ng-template>\n </p-multiSelect>\n @if (filterType() === FilterTypeEnum.String && enableCaseSensitive()) {\n <p-toggle-button\n [ngModel]=\"caseSensitiveModel()\"\n (ngModelChange)=\"caseSensitiveModel.set($event)\"\n [disabled]=\"disabled()\"\n name=\"caseSensitive\"\n class=\"mng-button-xs mng-toggle-button-addon-right\"\n onLabel=\"Aa\"\n offLabel=\"Aa\" />\n }\n</p-inputgroup>\n", dependencies: [{ kind: "component", type: Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "component", type: MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "directive", type: PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "component", type: ToggleButton, selector: "p-toggleButton, p-togglebutton, p-toggle-button", inputs: ["onLabel", "offLabel", "onIcon", "offIcon", "ariaLabel", "ariaLabelledBy", "styleClass", "inputId", "tabindex", "iconPos", "autofocus", "size", "allowEmpty", "fluid"], outputs: ["onChange"] }, { kind: "directive", type: InputTrimDirective, selector: "[mngInputTrim]", inputs: ["mngInputTrim"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1150
|
+
}
|
|
1151
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterFormMultiselectComponent, decorators: [{
|
|
1152
|
+
type: Component,
|
|
1153
|
+
args: [{ selector: 'mng-table-filter-form-multiselect', providers: [VALUE_ACCESSOR], imports: [Chip, FormsModule, InputNumber, MultiSelect, PrimeTemplate, TranslatePipe, InputGroup, InputText, ToggleButton, InputTrimDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p-inputgroup>\n <p-multiSelect\n [ngModel]=\"value()\"\n (ngModelChange)=\"value.set($event)\"\n [options]=\"value()\"\n [showToggleAll]=\"false\"\n [filter]=\"false\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [maxSelectedLabels]=\"1\"\n [selectedItemsLabel]=\"'mngDropdown.multiselectOverMaxDisplayLimit' | translate\"\n [selectAll]=\"false\"\n [disabled]=\"disabled()\"\n display=\"chip\"\n appendTo=\"body\"\n required=\"true\"\n panelStyleClass=\"table-filter-form-multiselect-panel p-2 flex flex-col gap-2 w-full max-w-72\">\n <ng-template pTemplate=\"header\">\n @if (filterType() === FilterTypeEnum.String) {\n <input\n type=\"text\"\n pInputText\n class=\"mng-filter-string w-full\"\n [disabled]=\"disabled()\"\n (keydown.enter)=\"onValueChange($event); $event.preventDefault()\"\n (keydown.tab)=\"onValueChange($event)\"\n (blur)=\"onValueChange($event)\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [mngInputTrim]=\"inputTrim()\" />\n } @else {\n <p-inputNumber\n inputStyleClass=\"mng-filter-number\"\n [disabled]=\"disabled()\"\n (keydown.enter)=\"onValueNumberChange($event); $event.preventDefault()\"\n (keydown.tab)=\"onValueNumberChange($event)\"\n (onBlur)=\"onValueNumberChange($event)\"\n [placeholder]=\"'mngFilter.value' | translate\"\n useGrouping=\"false\"\n required=\"true\" />\n }\n </ng-template>\n <ng-template pTemplate=\"footer\">\n <div class=\"flex flex-wrap gap-1 overflow-auto\">\n @if (value().length) {\n @for (val of stringValues(); track val; let i = $index) {\n <p-chip [label]=\"val\" removable (onRemove)=\"removeValue(i)\" />\n }\n } @else {\n <span class=\"p-1\">{{ 'mngFilter.noValues' | translate }}</span>\n }\n </div>\n </ng-template>\n </p-multiSelect>\n @if (filterType() === FilterTypeEnum.String && enableCaseSensitive()) {\n <p-toggle-button\n [ngModel]=\"caseSensitiveModel()\"\n (ngModelChange)=\"caseSensitiveModel.set($event)\"\n [disabled]=\"disabled()\"\n name=\"caseSensitive\"\n class=\"mng-button-xs mng-toggle-button-addon-right\"\n onLabel=\"Aa\"\n offLabel=\"Aa\" />\n }\n</p-inputgroup>\n" }]
|
|
1154
|
+
}], propDecorators: { filterType: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterType", required: false }] }], enableCaseSensitive: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableCaseSensitive", required: false }] }], caseSensitiveModel: [{ type: i0.Input, args: [{ isSignal: true, alias: "caseSensitiveModel", required: false }] }, { type: i0.Output, args: ["caseSensitiveModelChange"] }], inputTrim: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputTrim", required: false }] }], disabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }] } });
|
|
1155
|
+
|
|
1156
|
+
class TableFilterFormComponent {
|
|
1157
|
+
constructor() {
|
|
1158
|
+
this.lookupTypeDropdown = FilterLookupTypeEnum.Dropdown;
|
|
1159
|
+
this.lookupTypeAutocomplete = FilterLookupTypeEnum.Autocomplete;
|
|
1160
|
+
this.FilterTypeEnum = FilterTypeEnum;
|
|
1161
|
+
this.FilterMatchMode = FilterMatchMode;
|
|
1162
|
+
this.elementRef = inject(ElementRef);
|
|
1163
|
+
this.translate = inject(TranslateService);
|
|
1164
|
+
this.title = input(...(ngDevMode ? [undefined, { debugName: "title" }] : []));
|
|
1165
|
+
this.metadata = input.required(...(ngDevMode ? [{ debugName: "metadata" }] : []));
|
|
1166
|
+
this.genericDescriptor = input(...(ngDevMode ? [undefined, { debugName: "genericDescriptor" }] : []));
|
|
1167
|
+
this.model = input.required(...(ngDevMode ? [{ debugName: "model" }] : []));
|
|
1168
|
+
this.filter = input(...(ngDevMode ? [undefined, { debugName: "filter" }] : []));
|
|
1169
|
+
this.overlay = input(...(ngDevMode ? [undefined, { debugName: "overlay" }] : []));
|
|
1170
|
+
this.disabledProperties = input([], ...(ngDevMode ? [{ debugName: "disabledProperties" }] : []));
|
|
1171
|
+
this.enableCaseSensitive = input(true, ...(ngDevMode ? [{ debugName: "enableCaseSensitive" }] : []));
|
|
1172
|
+
this.propertySearch = input(false, ...(ngDevMode ? [{ debugName: "propertySearch", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
1173
|
+
this.apply = output();
|
|
1174
|
+
this.propertyOptionsWithTranslations = computed(() => {
|
|
1175
|
+
const disabledProperties = this.disabledProperties();
|
|
1176
|
+
const filter = this.filter();
|
|
1177
|
+
return (this.metadata()?.map(d => {
|
|
1178
|
+
return {
|
|
1179
|
+
property: d.descriptor.property,
|
|
1180
|
+
label: d.descriptor.isGenericFilter ? d.descriptor.property : this.getPropertyLabelKey(d.descriptor),
|
|
1181
|
+
disabled: !filter && disabledProperties.includes(d.descriptor.property)
|
|
1182
|
+
};
|
|
1183
|
+
}) ?? []);
|
|
1184
|
+
}, ...(ngDevMode ? [{ debugName: "propertyOptionsWithTranslations" }] : []));
|
|
1185
|
+
this.selectedFilterMetadata = computed(() => {
|
|
1186
|
+
const property = this.propertyModel();
|
|
1187
|
+
return this.metadata().find(d => d.descriptor.property === property);
|
|
1188
|
+
}, ...(ngDevMode ? [{ debugName: "selectedFilterMetadata" }] : []));
|
|
1189
|
+
// change value lookup function to include the property name of the generic filter
|
|
1190
|
+
this.genericValueDataProvider = computed(() => {
|
|
1191
|
+
const genericValueProvider = this.genericDescriptor()?.valueLookup;
|
|
1192
|
+
if (genericValueProvider && genericValueProvider.serviceType) {
|
|
1193
|
+
const lookupFn = genericValueProvider.lookup;
|
|
1194
|
+
return lookupDataProvider({ service: genericValueProvider.serviceType }).withLookup((params, service, search) => {
|
|
1195
|
+
params = {
|
|
1196
|
+
...params,
|
|
1197
|
+
filters: {
|
|
1198
|
+
...params?.filters,
|
|
1199
|
+
field: {
|
|
1200
|
+
value: this.selectedFilterMetadata()?.descriptor.property,
|
|
1201
|
+
matchMode: this.selectedFilterMetadata()?.descriptor.filterType === FilterTypeEnum.LookupEnum ? FilterMatchMode.In : FilterMatchMode.StartsWith
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
return lookupFn(params, service, search);
|
|
1206
|
+
});
|
|
1207
|
+
}
|
|
1208
|
+
return;
|
|
1209
|
+
}, ...(ngDevMode ? [{ debugName: "genericValueDataProvider" }] : []));
|
|
1210
|
+
this.selectedDescriptorAsLookup = computed(() => {
|
|
1211
|
+
const filterDescriptor = this.selectedFilterMetadata()?.descriptor;
|
|
1212
|
+
return filterDescriptor !== undefined &&
|
|
1213
|
+
!filterDescriptor.isGenericFilter &&
|
|
1214
|
+
(filterDescriptor.filterType === FilterTypeEnum.Lookup || filterDescriptor.filterType === FilterTypeEnum.LookupEnum)
|
|
1215
|
+
? filterDescriptor
|
|
1216
|
+
: undefined;
|
|
1217
|
+
}, ...(ngDevMode ? [{ debugName: "selectedDescriptorAsLookup" }] : []));
|
|
1218
|
+
this.isEdit = computed(() => this.filter() != null, ...(ngDevMode ? [{ debugName: "isEdit" }] : []));
|
|
1219
|
+
this.formSubmitted = signal(false, ...(ngDevMode ? [{ debugName: "formSubmitted" }] : []));
|
|
1220
|
+
this.formErrorMessage = signal([], ...(ngDevMode ? [{ debugName: "formErrorMessage" }] : []));
|
|
1221
|
+
// UI utilities
|
|
1222
|
+
this.filterForm = viewChild.required('filterForm');
|
|
1223
|
+
// Filter form model and form utilities
|
|
1224
|
+
this.propertyModel = signal(null, ...(ngDevMode ? [{ debugName: "propertyModel" }] : []));
|
|
1225
|
+
this.matchModeModel = signal(null, ...(ngDevMode ? [{ debugName: "matchModeModel" }] : []));
|
|
1226
|
+
this.valueModel = signal(null, ...(ngDevMode ? [{ debugName: "valueModel" }] : []));
|
|
1227
|
+
this.caseSensitiveModel = signal(false, ...(ngDevMode ? [{ debugName: "caseSensitiveModel" }] : []));
|
|
1228
|
+
this.isMultiselect = computed(() => this.matchModeModel() === FilterMatchMode.In || this.matchModeModel() === FilterMatchMode.NotIn, ...(ngDevMode ? [{ debugName: "isMultiselect" }] : []));
|
|
1229
|
+
this.addFilterShortcutText = isMac() ? '⌘ + /' : 'Ctrl + /';
|
|
1230
|
+
effectWithDeps([this.filter], ([edit]) => {
|
|
1231
|
+
if (edit) {
|
|
1232
|
+
this.resetForm({
|
|
1233
|
+
property: edit.config.descriptor.property,
|
|
1234
|
+
matchMode: edit.displayMatchMode ?? edit.matchMode ?? null,
|
|
1235
|
+
value: edit.displayValue ?? edit.value,
|
|
1236
|
+
caseSensitive: edit.caseSensitive ?? false
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1239
|
+
else {
|
|
1240
|
+
this.resetForm();
|
|
1241
|
+
}
|
|
1242
|
+
});
|
|
1243
|
+
effectWithDeps([this.selectedFilterMetadata], ([selectedFilterMetadata]) => {
|
|
1244
|
+
const descriptor = selectedFilterMetadata?.descriptor;
|
|
1245
|
+
const value = this.valueModel();
|
|
1246
|
+
if (value != null) {
|
|
1247
|
+
// reset value if filter type and value type mismatch
|
|
1248
|
+
if ((descriptor?.filterType === FilterTypeEnum.String && (value === true || value === false || value === 'true' || value === 'false' || value instanceof Date)) ||
|
|
1249
|
+
(descriptor?.filterType === FilterTypeEnum.Number &&
|
|
1250
|
+
(Array.isArray(value) ? value.some(v => typeof v !== 'number' || isNaN(v)) : typeof value !== 'number' && isNaN(+value))) ||
|
|
1251
|
+
(descriptor?.filterType === FilterTypeEnum.Date && !(value instanceof Date) && !(Array.isArray(value) && value.every(item => item instanceof Date)))) {
|
|
1252
|
+
this.valueModel.set(null);
|
|
1253
|
+
}
|
|
1254
|
+
else if (descriptor?.filterType === FilterTypeEnum.Boolean && typeof value !== 'boolean') {
|
|
1255
|
+
this.valueModel.set(false);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
const matchModeOptions = selectedFilterMetadata?.matchModes ?? [];
|
|
1259
|
+
const matchMode = this.matchModeModel();
|
|
1260
|
+
const filterForm = this.filterForm();
|
|
1261
|
+
const isEdit = this.isEdit();
|
|
1262
|
+
if (matchModeOptions.length > 0 &&
|
|
1263
|
+
(!matchMode ||
|
|
1264
|
+
(!isEdit && (filterForm.controls['matchMode']?.pristine || filterForm.controls['matchMode']?.untouched)) ||
|
|
1265
|
+
!matchModeOptions.find(o => o.value === matchMode))) {
|
|
1266
|
+
// reset match mode is needed
|
|
1267
|
+
this.matchModeModel.set(filterGetDefaultMatchMode(this.selectedFilterMetadata()?.descriptor, matchModeOptions));
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
effectWithDeps([this.matchModeModel], ([matchModeModel]) => this.valueModel.set(filterAdjustDisplayValueOnMatchModeChange(matchModeModel ?? undefined, this.valueModel())));
|
|
1271
|
+
toObservable(this.overlay)
|
|
1272
|
+
.pipe(switchMap(o => (o ? o.onShow : NEVER)), takeUntilDestroyed())
|
|
1273
|
+
.subscribe(() => {
|
|
1274
|
+
const formFields = this.elementRef.nativeElement.querySelectorAll('input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [role="combobox"]:not([disabled])');
|
|
1275
|
+
const activeEl = document.activeElement;
|
|
1276
|
+
const activeInputIdx = activeEl ? [...formFields].findIndex(el => activeEl.isEqualNode(el)) : 0;
|
|
1277
|
+
if (activeInputIdx <= 0) {
|
|
1278
|
+
formFields[0]?.focus();
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
onFormSubmit(form) {
|
|
1283
|
+
this.formSubmitted.set(true);
|
|
1284
|
+
// mark all as dirty
|
|
1285
|
+
for (const key in form.controls) {
|
|
1286
|
+
form.controls[key].markAsDirty();
|
|
1287
|
+
}
|
|
1288
|
+
const property = this.propertyModel();
|
|
1289
|
+
const matchMode = this.matchModeModel();
|
|
1290
|
+
if (form.invalid || !property || !matchMode) {
|
|
1291
|
+
this.formErrorMessage.set([
|
|
1292
|
+
{
|
|
1293
|
+
severity: 'warn',
|
|
1294
|
+
summary: this.translate.instant('mngFilter.messages.invalidFormTitle'),
|
|
1295
|
+
detail: this.translate.instant('mngFilter.messages.invalidFormMessage')
|
|
1296
|
+
}
|
|
1297
|
+
]);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
this.apply.emit({
|
|
1301
|
+
property: property,
|
|
1302
|
+
matchMode: matchMode,
|
|
1303
|
+
value: this.valueModel(),
|
|
1304
|
+
caseSensitive: this.caseSensitiveModel()
|
|
1305
|
+
});
|
|
1306
|
+
// resetting the form is done from the parent component (filter-overlay-with-tag) for smoother animations
|
|
1307
|
+
}
|
|
1308
|
+
resetForm(value) {
|
|
1309
|
+
// somehow have to set case sensitivity manually
|
|
1310
|
+
this.propertyModel.set(value?.property ?? null);
|
|
1311
|
+
this.matchModeModel.set(value?.matchMode ?? null);
|
|
1312
|
+
this.valueModel.set(value?.value ?? null);
|
|
1313
|
+
this.caseSensitiveModel.set(value?.caseSensitive ?? false);
|
|
1314
|
+
// submitted control
|
|
1315
|
+
this.formSubmitted.set(false);
|
|
1316
|
+
}
|
|
1317
|
+
getPropertyLabelKey(filterDescriptor) {
|
|
1318
|
+
let labelKey;
|
|
1319
|
+
if (filterDescriptor.title !== undefined && !filterDescriptor.titleUseModelBase) {
|
|
1320
|
+
labelKey = filterDescriptor.title;
|
|
1321
|
+
}
|
|
1322
|
+
else {
|
|
1323
|
+
labelKey = getI18nTypePropertyKey(this.model().i18nBaseKey, filterDescriptor.title ?? filterDescriptor.property);
|
|
1324
|
+
}
|
|
1325
|
+
return labelKey;
|
|
1326
|
+
}
|
|
1327
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1328
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableFilterFormComponent, isStandalone: true, selector: "mng-table-filter-form", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: true, transformFunction: null }, genericDescriptor: { classPropertyName: "genericDescriptor", publicName: "genericDescriptor", isSignal: true, isRequired: false, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, overlay: { classPropertyName: "overlay", publicName: "overlay", isSignal: true, isRequired: false, transformFunction: null }, disabledProperties: { classPropertyName: "disabledProperties", publicName: "disabledProperties", isSignal: true, isRequired: false, transformFunction: null }, enableCaseSensitive: { classPropertyName: "enableCaseSensitive", publicName: "enableCaseSensitive", isSignal: true, isRequired: false, transformFunction: null }, propertySearch: { classPropertyName: "propertySearch", publicName: "propertySearch", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { apply: "apply" }, host: { classAttribute: "flex grow" }, viewQueries: [{ propertyName: "filterForm", first: true, predicate: ["filterForm"], descendants: true, isSignal: true }], ngImport: i0, template: "<div>\n <div class=\"flex items-center gap-2\">\n <h5>{{ filter() ? ('mngFilter.titleEdit' | translate) : ('mngFilter.titleAdd' | translate) }}</h5>\n @if (!filter()) {\n <div class=\"text-sm opacity-50 font-normal self-start pt-[2px]\">( {{ addFilterShortcutText }} )</div>\n }\n </div>\n <form #filterForm=\"ngForm\" (ngSubmit)=\"onFormSubmit(filterForm)\" class=\"flex flex-col items-baseline lg:flex-row gap-4\">\n <div class=\"w-full lg:w-auto\">\n <mng-dropdown\n name=\"property\"\n id=\"property\"\n tabindex=\"1\"\n #propertyControl=\"ngModel\"\n [(ngModel)]=\"propertyModel\"\n [options]=\"propertyOptionsWithTranslations()\"\n optionsValueProperty=\"property\"\n optionsDisabledProperty=\"disabled\"\n optionsLabelProperty=\"label\"\n [placeholder]=\"'mngFilter.property' | translate\"\n [optionsLabelTranslate]=\"!propertySearch()\"\n [inlineSearch]=\"propertySearch()\"\n required=\"true\"\n className=\"w-full\"\n [disabled]=\"isEdit()\"\n [appendTo]=\"null\" />\n </div>\n <div class=\"w-full lg:w-auto\">\n <mng-dropdown\n name=\"matchMode\"\n id=\"matchMode\"\n [(ngModel)]=\"matchModeModel\"\n className=\"w-full\"\n [options]=\"selectedFilterMetadata()?.matchModes ?? []\"\n [placeholder]=\"'mngFilter.matchMode' | translate\"\n [disabled]=\"!propertyControl.value\"\n class=\"self-end\"\n required=\"true\"\n [appendTo]=\"null\" />\n </div>\n @if (!(matchModeModel() === FilterMatchMode.Exists || matchModeModel() === FilterMatchMode.DoesNotExist)) {\n <div class=\"w-full lg:w-auto flex flex-col\">\n @switch (selectedFilterMetadata()?.descriptor?.filterType) {\n @case (FilterTypeEnum.Number) {\n @if (matchModeModel() === FilterMatchMode.In || matchModeModel() === FilterMatchMode.NotIn) {\n <mng-table-filter-form-multiselect\n name=\"value\"\n [(ngModel)]=\"valueModel\"\n [filterType]=\"selectedFilterMetadata()?.descriptor?.filterType\"\n [disabled]=\"!matchModeModel()\" />\n } @else if (matchModeModel() === FilterMatchMode.Between) {\n <mng-number-range\n className=\"mng-filter-number\"\n name=\"value\"\n [(ngModel)]=\"valueModel\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [useGrouping]=\"selectedFilterMetadata()?.descriptor?.numberUseGrouping ?? false\"\n [minFractionDigits]=\"selectedFilterMetadata()?.numberConfig?.fractionsMin\"\n [maxFractionDigits]=\"selectedFilterMetadata()?.numberConfig?.fractionsMax\"\n required=\"true\" />\n } @else {\n <p-inputNumber\n inputStyleClass=\"mng-filter-number\"\n name=\"value\"\n [(ngModel)]=\"valueModel\"\n [styleClass]=\"'w-full'\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [useGrouping]=\"selectedFilterMetadata()?.descriptor?.numberUseGrouping\"\n [minFractionDigits]=\"selectedFilterMetadata()?.numberConfig?.fractionsMin\"\n [maxFractionDigits]=\"selectedFilterMetadata()?.numberConfig?.fractionsMax\"\n [disabled]=\"!matchModeModel()\"\n required=\"true\" />\n }\n }\n\n @case (FilterTypeEnum.Boolean) {\n <p-checkbox [(ngModel)]=\"valueModel\" [disabled]=\"!matchModeModel()\" name=\"value\" binary=\"true\" required=\"true\" />\n }\n @case (FilterTypeEnum.Date) {\n @if (matchModeModel() === FilterMatchMode.Between) {\n <mng-date-range\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n vertical=\"true\"\n [showTime]=\"selectedFilterMetadata()?.dateConfig?.showTime\"\n [showSeconds]=\"selectedFilterMetadata()?.dateConfig?.showSeconds\"\n [milliseconds]=\"selectedFilterMetadata()?.dateConfig?.showMilliseconds\"\n [primeTimePicker]=\"selectedFilterMetadata()?.dateConfig?.primeTimePicker\"\n [timeSelect]=\"selectedFilterMetadata()?.dateConfig?.timeSelect\"\n [timeSelectInterval]=\"selectedFilterMetadata()?.dateConfig?.timeSelectInterval\"\n [dateFormat]=\"selectedFilterMetadata()?.dateConfig?.format\"\n [placeholder]=\"'mngFilter.value' | translate\"\n required=\"true\" />\n } @else {\n <mng-datetime-picker\n name=\"value\"\n className=\"w-full\"\n [(ngModel)]=\"valueModel\"\n [placeholder]=\"'mngFilter.value' | translate\"\n showIcon=\"true\"\n [time]=\"selectedFilterMetadata()?.dateConfig?.showTime\"\n [seconds]=\"selectedFilterMetadata()?.dateConfig?.showSeconds\"\n [milliseconds]=\"selectedFilterMetadata()?.dateConfig?.showMilliseconds\"\n [primeTimePicker]=\"selectedFilterMetadata()?.dateConfig?.primeTimePicker\"\n [timeSelect]=\"selectedFilterMetadata()?.dateConfig?.timeSelect\"\n [timeSelectInterval]=\"selectedFilterMetadata()?.dateConfig?.timeSelectInterval\"\n [dateFormat]=\"selectedFilterMetadata()?.dateConfig?.format\"\n [disabled]=\"!matchModeModel()\"\n required=\"true\" />\n }\n }\n @case (FilterTypeEnum.Lookup) {\n <ng-container *ngTemplateOutlet=\"lookupFilter\"></ng-container>\n }\n @case (FilterTypeEnum.LookupEnum) {\n <ng-container *ngTemplateOutlet=\"lookupFilter\"></ng-container>\n }\n @default {\n @if (selectedFilterMetadata()?.descriptor?.genericValueProvider && genericValueDataProvider()) {\n <div class=\"flex\">\n <mng-dropdown\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n [dataProvider]=\"genericValueDataProvider()\"\n [className]=\"selectedFilterMetadata()?.descriptor?.className + ' ' + (enableCaseSensitive() ? 'rounded-r-none!' : '')\"\n [dropdownClassName]=\"selectedFilterMetadata()?.descriptor?.dropdownClassName\"\n [placeholder]=\"valueModel() ? undefined : ('mngFilter.value' | translate)\"\n allowInput=\"true\"\n [disabled]=\"!matchModeModel()\"\n [appendTo]=\"null\"\n required=\"true\" />\n @if (enableCaseSensitive()) {\n <p-toggle-button\n [(ngModel)]=\"caseSensitiveModel\"\n [disabled]=\"!matchModeModel()\"\n name=\"caseSensitive\"\n styleClass=\"mng-button-xs mng-toggle-button-addon-right\"\n onLabel=\"Aa\"\n offLabel=\"Aa\" />\n }\n </div>\n } @else if (matchModeModel() === FilterMatchMode.In || matchModeModel() === FilterMatchMode.NotIn) {\n <mng-table-filter-form-multiselect\n name=\"value\"\n [(ngModel)]=\"valueModel\"\n [filterType]=\"selectedFilterMetadata()?.descriptor?.filterType\"\n [enableCaseSensitive]=\"enableCaseSensitive()\"\n [(caseSensitiveModel)]=\"caseSensitiveModel\"\n [inputTrim]=\"selectedFilterMetadata()?.descriptor?.trimOption\"\n [disabled]=\"!matchModeModel()\" />\n } @else {\n <div class=\"flex\">\n <input\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n type=\"text\"\n pInputText\n class=\"mng-filter-string w-full\"\n [class.rounded-r-none!]=\"enableCaseSensitive()\"\n [attr.placeholder]=\"'mngFilter.value' | translate\"\n [mngInputTrim]=\"selectedFilterMetadata()?.descriptor?.trimOption\"\n [disabled]=\"!matchModeModel()\"\n [placeholder]=\"'mngFilter.value' | translate\"\n required=\"true\" />\n @if (enableCaseSensitive()) {\n <p-toggle-button\n [(ngModel)]=\"caseSensitiveModel\"\n [disabled]=\"!matchModeModel()\"\n name=\"caseSensitive\"\n styleClass=\"mng-button-xs mng-toggle-button-addon-right\"\n onLabel=\"Aa\"\n offLabel=\"Aa\" />\n }\n </div>\n }\n }\n }\n <ng-template #lookupFilter>\n @if (selectedDescriptorAsLookup(); as lookupFilterDescriptor) {\n @switch (lookupFilterDescriptor.lookupType) {\n @case (lookupTypeAutocomplete) {\n <mng-autocomplete\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n [dataProvider]=\"lookupFilterDescriptor.dataProvider\"\n [optionsTrackProperty]=\"lookupFilterDescriptor.optionsValueProperty\"\n [optionsValueProperty]=\"lookupFilterDescriptor.optionsValueProperty\"\n [optionsLabelProperty]=\"lookupFilterDescriptor.optionsLabelProperty\"\n [optionsLabelTranslate]=\"lookupFilterDescriptor.optionsLabelTranslate\"\n [multiselect]=\"isMultiselect()\"\n [autoClear]=\"lookupFilterDescriptor.autocompleteAutoClear ?? false\"\n [openOnFocus]=\"lookupFilterDescriptor.autocompleteAutoClear ?? true\"\n [inlineSearch]=\"lookupFilterDescriptor.autocompleteInlineSearch ?? false\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [className]=\"lookupFilterDescriptor.className\"\n [dropdownClassName]=\"lookupFilterDescriptor.dropdownClassName\"\n [searchTrim]=\"selectedFilterMetadata()?.descriptor?.trimOption\"\n [disabled]=\"!matchModeModel()\"\n required=\"true\">\n </mng-autocomplete>\n }\n @case (lookupTypeDropdown) {\n <mng-dropdown\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n [dataProvider]=\"lookupFilterDescriptor.dataProvider\"\n [optionsValueProperty]=\"lookupFilterDescriptor.optionsValueProperty\"\n [optionsLabelProperty]=\"lookupFilterDescriptor.optionsLabelProperty\"\n [optionsLabelTranslate]=\"lookupFilterDescriptor.optionsLabelTranslate\"\n [multiselect]=\"isMultiselect()\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [className]=\"lookupFilterDescriptor.className + ' w-full'\"\n [dropdownClassName]=\"lookupFilterDescriptor.dropdownClassName\"\n showClear=\"false\"\n [disabled]=\"!matchModeModel()\"\n [appendTo]=\"null\"\n required=\"true\">\n </mng-dropdown>\n }\n }\n } @else if (selectedFilterMetadata()?.descriptor?.isGenericFilter && genericValueDataProvider()) {\n <mng-dropdown\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n [dataProvider]=\"genericValueDataProvider()\"\n [placeholder]=\"'mngFilter.value' | translate\"\n showClear=\"false\"\n [disabled]=\"!matchModeModel()\"\n [appendTo]=\"null\"\n required=\"true\">\n </mng-dropdown>\n }\n </ng-template>\n </div>\n }\n <div class=\"flex justify-end\">\n <button pButton type=\"submit\" class=\"mng-filter-submit-button self-end\">\n {{ (filter() ? 'general.apply' : 'general.add') | translate }}\n </button>\n </div>\n </form>\n @if (formSubmitted() && filterForm.invalid) {\n @for (message of formErrorMessage(); track message) {\n <p-message [severity]=\"message.severity\" [text]=\"message.detail\" [icon]=\"message.icon\" styleClass=\"mt-2\" />\n }\n }\n</div>\n", styles: [".mng-toggle-button-addon-right{border-color:var(--p-select-border-color)!important;border-left:none!important;border-top-left-radius:0!important;border-bottom-left-radius:0!important;min-width:35px}.mng-toggle-button-addon-right .p-togglebutton-content{padding-left:.25rem;padding-right:.25rem}.table-filter-form-multiselect-panel .p-multiselect-list-container,.table-filter-form-multiselect-panel .p-multiselect-header{display:none!important}\n"], dependencies: [{ kind: "component", type: DropdownComponent, selector: "mng-dropdown", inputs: ["dataProvider", "options", "optionsTrackProperty", "optionsLabelProperty", "optionsLabelTranslate", "optionsValueProperty", "optionsDisabledProperty", "multiselect", "placeholder", "showClear", "selectFirstItem", "className", "dropdownClassName", "changeValueOnBlur", "loading", "disabled", "allowInput", "appendTo", "templates", "inlineSearch", "searchTrim"], outputs: ["valueChange", "blur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: InputTrimDirective, selector: "[mngInputTrim]", inputs: ["mngInputTrim"] }, { kind: "component", type: NumberRangeComponent, selector: "mng-number-range", inputs: ["placeholder", "useGrouping", "minFractionDigits", "maxFractionDigits", "required", "disabled", "vertical", "templates", "className"], outputs: ["keyDown"] }, { kind: "component", type: InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "placeholder", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "autocomplete", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "component", type: DateRangeComponent, selector: "mng-date-range", inputs: ["placeholder", "showTime", "showSeconds", "milliseconds", "primeTimePicker", "timeSelect", "timeSelectInterval", "dateFormat", "className", "inputStyleClass", "required", "disabled", "vertical", "templates"] }, { kind: "component", type: AutocompleteComponent, selector: "mng-autocomplete", inputs: ["dataProvider", "optionsTrackProperty", "optionsValueProperty", "optionsLabelProperty", "optionsLabelTranslate", "inlineSearch", "openOnFocus", "multiselect", "placeholder", "className", "dropdownClassName", "showClear", "autoClear", "selectFirst", "searchTrim", "disabled", "templates"], outputs: ["valueChange", "blur"] }, { kind: "component", type: Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "component", type: Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ToggleButton, selector: "p-toggleButton, p-togglebutton, p-toggle-button", inputs: ["onLabel", "offLabel", "onIcon", "offIcon", "ariaLabel", "ariaLabelledBy", "styleClass", "inputId", "tabindex", "iconPos", "autofocus", "size", "allowEmpty", "fluid"], outputs: ["onChange"] }, { kind: "directive", type: ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "component", type: TableFilterFormMultiselectComponent, selector: "mng-table-filter-form-multiselect", inputs: ["filterType", "enableCaseSensitive", "caseSensitiveModel", "inputTrim", "disabled"], outputs: ["caseSensitiveModelChange"] }, { kind: "component", type: DatetimePickerComponent, selector: "mng-datetime-picker", inputs: ["templates", "time", "timeSelect", "timeSelectInterval", "seconds", "milliseconds", "primeTimePicker", "dateFormat", "placeholder", "minDate", "maxDate", "disabled", "required", "showIcon", "showButtonBar", "showClear", "className", "panelStyleClass", "inputStyleClass", "dateRange"], outputs: ["blur"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
1329
|
+
}
|
|
1330
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterFormComponent, decorators: [{
|
|
1331
|
+
type: Component,
|
|
1332
|
+
args: [{ selector: 'mng-table-filter-form', imports: [
|
|
1333
|
+
DropdownComponent,
|
|
1334
|
+
FormsModule,
|
|
1335
|
+
TranslatePipe,
|
|
1336
|
+
InputTrimDirective,
|
|
1337
|
+
NumberRangeComponent,
|
|
1338
|
+
InputNumber,
|
|
1339
|
+
DateRangeComponent,
|
|
1340
|
+
AutocompleteComponent,
|
|
1341
|
+
Checkbox,
|
|
1342
|
+
Message,
|
|
1343
|
+
InputText,
|
|
1344
|
+
NgTemplateOutlet,
|
|
1345
|
+
ToggleButton,
|
|
1346
|
+
ButtonDirective,
|
|
1347
|
+
TableFilterFormMultiselectComponent,
|
|
1348
|
+
DatetimePickerComponent
|
|
1349
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1350
|
+
class: 'flex grow'
|
|
1351
|
+
}, encapsulation: ViewEncapsulation.None, template: "<div>\n <div class=\"flex items-center gap-2\">\n <h5>{{ filter() ? ('mngFilter.titleEdit' | translate) : ('mngFilter.titleAdd' | translate) }}</h5>\n @if (!filter()) {\n <div class=\"text-sm opacity-50 font-normal self-start pt-[2px]\">( {{ addFilterShortcutText }} )</div>\n }\n </div>\n <form #filterForm=\"ngForm\" (ngSubmit)=\"onFormSubmit(filterForm)\" class=\"flex flex-col items-baseline lg:flex-row gap-4\">\n <div class=\"w-full lg:w-auto\">\n <mng-dropdown\n name=\"property\"\n id=\"property\"\n tabindex=\"1\"\n #propertyControl=\"ngModel\"\n [(ngModel)]=\"propertyModel\"\n [options]=\"propertyOptionsWithTranslations()\"\n optionsValueProperty=\"property\"\n optionsDisabledProperty=\"disabled\"\n optionsLabelProperty=\"label\"\n [placeholder]=\"'mngFilter.property' | translate\"\n [optionsLabelTranslate]=\"!propertySearch()\"\n [inlineSearch]=\"propertySearch()\"\n required=\"true\"\n className=\"w-full\"\n [disabled]=\"isEdit()\"\n [appendTo]=\"null\" />\n </div>\n <div class=\"w-full lg:w-auto\">\n <mng-dropdown\n name=\"matchMode\"\n id=\"matchMode\"\n [(ngModel)]=\"matchModeModel\"\n className=\"w-full\"\n [options]=\"selectedFilterMetadata()?.matchModes ?? []\"\n [placeholder]=\"'mngFilter.matchMode' | translate\"\n [disabled]=\"!propertyControl.value\"\n class=\"self-end\"\n required=\"true\"\n [appendTo]=\"null\" />\n </div>\n @if (!(matchModeModel() === FilterMatchMode.Exists || matchModeModel() === FilterMatchMode.DoesNotExist)) {\n <div class=\"w-full lg:w-auto flex flex-col\">\n @switch (selectedFilterMetadata()?.descriptor?.filterType) {\n @case (FilterTypeEnum.Number) {\n @if (matchModeModel() === FilterMatchMode.In || matchModeModel() === FilterMatchMode.NotIn) {\n <mng-table-filter-form-multiselect\n name=\"value\"\n [(ngModel)]=\"valueModel\"\n [filterType]=\"selectedFilterMetadata()?.descriptor?.filterType\"\n [disabled]=\"!matchModeModel()\" />\n } @else if (matchModeModel() === FilterMatchMode.Between) {\n <mng-number-range\n className=\"mng-filter-number\"\n name=\"value\"\n [(ngModel)]=\"valueModel\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [useGrouping]=\"selectedFilterMetadata()?.descriptor?.numberUseGrouping ?? false\"\n [minFractionDigits]=\"selectedFilterMetadata()?.numberConfig?.fractionsMin\"\n [maxFractionDigits]=\"selectedFilterMetadata()?.numberConfig?.fractionsMax\"\n required=\"true\" />\n } @else {\n <p-inputNumber\n inputStyleClass=\"mng-filter-number\"\n name=\"value\"\n [(ngModel)]=\"valueModel\"\n [styleClass]=\"'w-full'\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [useGrouping]=\"selectedFilterMetadata()?.descriptor?.numberUseGrouping\"\n [minFractionDigits]=\"selectedFilterMetadata()?.numberConfig?.fractionsMin\"\n [maxFractionDigits]=\"selectedFilterMetadata()?.numberConfig?.fractionsMax\"\n [disabled]=\"!matchModeModel()\"\n required=\"true\" />\n }\n }\n\n @case (FilterTypeEnum.Boolean) {\n <p-checkbox [(ngModel)]=\"valueModel\" [disabled]=\"!matchModeModel()\" name=\"value\" binary=\"true\" required=\"true\" />\n }\n @case (FilterTypeEnum.Date) {\n @if (matchModeModel() === FilterMatchMode.Between) {\n <mng-date-range\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n vertical=\"true\"\n [showTime]=\"selectedFilterMetadata()?.dateConfig?.showTime\"\n [showSeconds]=\"selectedFilterMetadata()?.dateConfig?.showSeconds\"\n [milliseconds]=\"selectedFilterMetadata()?.dateConfig?.showMilliseconds\"\n [primeTimePicker]=\"selectedFilterMetadata()?.dateConfig?.primeTimePicker\"\n [timeSelect]=\"selectedFilterMetadata()?.dateConfig?.timeSelect\"\n [timeSelectInterval]=\"selectedFilterMetadata()?.dateConfig?.timeSelectInterval\"\n [dateFormat]=\"selectedFilterMetadata()?.dateConfig?.format\"\n [placeholder]=\"'mngFilter.value' | translate\"\n required=\"true\" />\n } @else {\n <mng-datetime-picker\n name=\"value\"\n className=\"w-full\"\n [(ngModel)]=\"valueModel\"\n [placeholder]=\"'mngFilter.value' | translate\"\n showIcon=\"true\"\n [time]=\"selectedFilterMetadata()?.dateConfig?.showTime\"\n [seconds]=\"selectedFilterMetadata()?.dateConfig?.showSeconds\"\n [milliseconds]=\"selectedFilterMetadata()?.dateConfig?.showMilliseconds\"\n [primeTimePicker]=\"selectedFilterMetadata()?.dateConfig?.primeTimePicker\"\n [timeSelect]=\"selectedFilterMetadata()?.dateConfig?.timeSelect\"\n [timeSelectInterval]=\"selectedFilterMetadata()?.dateConfig?.timeSelectInterval\"\n [dateFormat]=\"selectedFilterMetadata()?.dateConfig?.format\"\n [disabled]=\"!matchModeModel()\"\n required=\"true\" />\n }\n }\n @case (FilterTypeEnum.Lookup) {\n <ng-container *ngTemplateOutlet=\"lookupFilter\"></ng-container>\n }\n @case (FilterTypeEnum.LookupEnum) {\n <ng-container *ngTemplateOutlet=\"lookupFilter\"></ng-container>\n }\n @default {\n @if (selectedFilterMetadata()?.descriptor?.genericValueProvider && genericValueDataProvider()) {\n <div class=\"flex\">\n <mng-dropdown\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n [dataProvider]=\"genericValueDataProvider()\"\n [className]=\"selectedFilterMetadata()?.descriptor?.className + ' ' + (enableCaseSensitive() ? 'rounded-r-none!' : '')\"\n [dropdownClassName]=\"selectedFilterMetadata()?.descriptor?.dropdownClassName\"\n [placeholder]=\"valueModel() ? undefined : ('mngFilter.value' | translate)\"\n allowInput=\"true\"\n [disabled]=\"!matchModeModel()\"\n [appendTo]=\"null\"\n required=\"true\" />\n @if (enableCaseSensitive()) {\n <p-toggle-button\n [(ngModel)]=\"caseSensitiveModel\"\n [disabled]=\"!matchModeModel()\"\n name=\"caseSensitive\"\n styleClass=\"mng-button-xs mng-toggle-button-addon-right\"\n onLabel=\"Aa\"\n offLabel=\"Aa\" />\n }\n </div>\n } @else if (matchModeModel() === FilterMatchMode.In || matchModeModel() === FilterMatchMode.NotIn) {\n <mng-table-filter-form-multiselect\n name=\"value\"\n [(ngModel)]=\"valueModel\"\n [filterType]=\"selectedFilterMetadata()?.descriptor?.filterType\"\n [enableCaseSensitive]=\"enableCaseSensitive()\"\n [(caseSensitiveModel)]=\"caseSensitiveModel\"\n [inputTrim]=\"selectedFilterMetadata()?.descriptor?.trimOption\"\n [disabled]=\"!matchModeModel()\" />\n } @else {\n <div class=\"flex\">\n <input\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n type=\"text\"\n pInputText\n class=\"mng-filter-string w-full\"\n [class.rounded-r-none!]=\"enableCaseSensitive()\"\n [attr.placeholder]=\"'mngFilter.value' | translate\"\n [mngInputTrim]=\"selectedFilterMetadata()?.descriptor?.trimOption\"\n [disabled]=\"!matchModeModel()\"\n [placeholder]=\"'mngFilter.value' | translate\"\n required=\"true\" />\n @if (enableCaseSensitive()) {\n <p-toggle-button\n [(ngModel)]=\"caseSensitiveModel\"\n [disabled]=\"!matchModeModel()\"\n name=\"caseSensitive\"\n styleClass=\"mng-button-xs mng-toggle-button-addon-right\"\n onLabel=\"Aa\"\n offLabel=\"Aa\" />\n }\n </div>\n }\n }\n }\n <ng-template #lookupFilter>\n @if (selectedDescriptorAsLookup(); as lookupFilterDescriptor) {\n @switch (lookupFilterDescriptor.lookupType) {\n @case (lookupTypeAutocomplete) {\n <mng-autocomplete\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n [dataProvider]=\"lookupFilterDescriptor.dataProvider\"\n [optionsTrackProperty]=\"lookupFilterDescriptor.optionsValueProperty\"\n [optionsValueProperty]=\"lookupFilterDescriptor.optionsValueProperty\"\n [optionsLabelProperty]=\"lookupFilterDescriptor.optionsLabelProperty\"\n [optionsLabelTranslate]=\"lookupFilterDescriptor.optionsLabelTranslate\"\n [multiselect]=\"isMultiselect()\"\n [autoClear]=\"lookupFilterDescriptor.autocompleteAutoClear ?? false\"\n [openOnFocus]=\"lookupFilterDescriptor.autocompleteAutoClear ?? true\"\n [inlineSearch]=\"lookupFilterDescriptor.autocompleteInlineSearch ?? false\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [className]=\"lookupFilterDescriptor.className\"\n [dropdownClassName]=\"lookupFilterDescriptor.dropdownClassName\"\n [searchTrim]=\"selectedFilterMetadata()?.descriptor?.trimOption\"\n [disabled]=\"!matchModeModel()\"\n required=\"true\">\n </mng-autocomplete>\n }\n @case (lookupTypeDropdown) {\n <mng-dropdown\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n [dataProvider]=\"lookupFilterDescriptor.dataProvider\"\n [optionsValueProperty]=\"lookupFilterDescriptor.optionsValueProperty\"\n [optionsLabelProperty]=\"lookupFilterDescriptor.optionsLabelProperty\"\n [optionsLabelTranslate]=\"lookupFilterDescriptor.optionsLabelTranslate\"\n [multiselect]=\"isMultiselect()\"\n [placeholder]=\"'mngFilter.value' | translate\"\n [className]=\"lookupFilterDescriptor.className + ' w-full'\"\n [dropdownClassName]=\"lookupFilterDescriptor.dropdownClassName\"\n showClear=\"false\"\n [disabled]=\"!matchModeModel()\"\n [appendTo]=\"null\"\n required=\"true\">\n </mng-dropdown>\n }\n }\n } @else if (selectedFilterMetadata()?.descriptor?.isGenericFilter && genericValueDataProvider()) {\n <mng-dropdown\n [(ngModel)]=\"valueModel\"\n name=\"value\"\n [dataProvider]=\"genericValueDataProvider()\"\n [placeholder]=\"'mngFilter.value' | translate\"\n showClear=\"false\"\n [disabled]=\"!matchModeModel()\"\n [appendTo]=\"null\"\n required=\"true\">\n </mng-dropdown>\n }\n </ng-template>\n </div>\n }\n <div class=\"flex justify-end\">\n <button pButton type=\"submit\" class=\"mng-filter-submit-button self-end\">\n {{ (filter() ? 'general.apply' : 'general.add') | translate }}\n </button>\n </div>\n </form>\n @if (formSubmitted() && filterForm.invalid) {\n @for (message of formErrorMessage(); track message) {\n <p-message [severity]=\"message.severity\" [text]=\"message.detail\" [icon]=\"message.icon\" styleClass=\"mt-2\" />\n }\n }\n</div>\n", styles: [".mng-toggle-button-addon-right{border-color:var(--p-select-border-color)!important;border-left:none!important;border-top-left-radius:0!important;border-bottom-left-radius:0!important;min-width:35px}.mng-toggle-button-addon-right .p-togglebutton-content{padding-left:.25rem;padding-right:.25rem}.table-filter-form-multiselect-panel .p-multiselect-list-container,.table-filter-form-multiselect-panel .p-multiselect-header{display:none!important}\n"] }]
|
|
1352
|
+
}], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], metadata: [{ type: i0.Input, args: [{ isSignal: true, alias: "metadata", required: true }] }], genericDescriptor: [{ type: i0.Input, args: [{ isSignal: true, alias: "genericDescriptor", required: false }] }], model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], overlay: [{ type: i0.Input, args: [{ isSignal: true, alias: "overlay", required: false }] }], disabledProperties: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledProperties", required: false }] }], enableCaseSensitive: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableCaseSensitive", required: false }] }], propertySearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "propertySearch", required: false }] }], apply: [{ type: i0.Output, args: ["apply"] }], filterForm: [{ type: i0.ViewChild, args: ['filterForm', { isSignal: true }] }] } });
|
|
1353
|
+
|
|
1354
|
+
const COMMONS_TABLE_FEATURE_CONFIG_IT = new InjectionToken('COMMONS_TABLE_FEATURE_CONFIG');
|
|
1355
|
+
|
|
1356
|
+
class TableHeaderWithFiltersTemplateDirective extends TemplateDirective {
|
|
1357
|
+
constructor() {
|
|
1358
|
+
super(...arguments);
|
|
1359
|
+
this.name = input.required(...(ngDevMode ? [{ debugName: "name" }] : []));
|
|
1360
|
+
}
|
|
1361
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableHeaderWithFiltersTemplateDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1362
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.15", type: TableHeaderWithFiltersTemplateDirective, isStandalone: true, selector: "[mngTableHeaderWithFiltersTemplate]", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0 }); }
|
|
1363
|
+
}
|
|
1364
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableHeaderWithFiltersTemplateDirective, decorators: [{
|
|
1365
|
+
type: Directive,
|
|
1366
|
+
args: [{
|
|
1367
|
+
selector: '[mngTableHeaderWithFiltersTemplate]'
|
|
1368
|
+
}]
|
|
1369
|
+
}], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }] } });
|
|
1370
|
+
|
|
1371
|
+
class TableHeaderWithFiltersComponent {
|
|
1372
|
+
static { this.SEARCH_WORD_LIMIT_MAX = 4; }
|
|
1373
|
+
constructor() {
|
|
1374
|
+
this.translateService = inject(TranslateService);
|
|
1375
|
+
this.tableData = inject((ADataListService));
|
|
1376
|
+
this.tableConfig = inject(COMMONS_TABLE_FEATURE_CONFIG_IT, { optional: true });
|
|
1377
|
+
this.defaultFilterDisplayType = this.tableConfig?.filterDisplayType ?? FilterDisplayTypeEnum.Column;
|
|
1378
|
+
this.metadata = input.required(...(ngDevMode ? [{ debugName: "metadata" }] : []));
|
|
1379
|
+
this.genericFilterDescriptor = input(...(ngDevMode ? [undefined, { debugName: "genericFilterDescriptor" }] : []));
|
|
1380
|
+
this.model = input.required(...(ngDevMode ? [{ debugName: "model" }] : []));
|
|
1381
|
+
this.enableSearch = input(false, ...(ngDevMode ? [{ debugName: "enableSearch", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
1382
|
+
this.search = input(...(ngDevMode ? [undefined, { debugName: "search" }] : []));
|
|
1383
|
+
this.searchLimitWordMax = input(undefined, ...(ngDevMode ? [{ debugName: "searchLimitWordMax" }] : []));
|
|
1384
|
+
this.enableCaseSensitive = input(true, ...(ngDevMode ? [{ debugName: "enableCaseSensitive", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
1385
|
+
this.filterMenuItems = signal([], ...(ngDevMode ? [{ debugName: "filterMenuItems" }] : []));
|
|
1386
|
+
this.filterOverlay = viewChild.required(Popover);
|
|
1387
|
+
this.filterFormComponent = viewChild(TableFilterFormComponent, ...(ngDevMode ? [{ debugName: "filterFormComponent" }] : []));
|
|
1388
|
+
this.templates = contentChildren(TableHeaderWithFiltersTemplateDirective, ...(ngDevMode ? [{ debugName: "templates" }] : []));
|
|
1389
|
+
this.titleTemplate = computed(() => findTemplateByName([...this.templates()], 'title'), ...(ngDevMode ? [{ debugName: "titleTemplate" }] : []));
|
|
1390
|
+
this.titleRowRightTemplate = computed(() => findTemplateByName([...this.templates()], 'titleRowRight'), ...(ngDevMode ? [{ debugName: "titleRowRightTemplate" }] : []));
|
|
1391
|
+
this.overlayFormMetadata = computed(() => this.metadata().filter(f => (f.descriptor.displayType == null && FilterDisplayTypeEnum.OverlayWithTag === this.defaultFilterDisplayType) ||
|
|
1392
|
+
f.descriptor.displayType === FilterDisplayTypeEnum.OverlayWithTag), ...(ngDevMode ? [{ debugName: "overlayFormMetadata" }] : []));
|
|
1393
|
+
this.directInputMetadata = computed(() => this.metadata().filter(f => (f.descriptor.displayType == null && FilterDisplayTypeEnum.DirectInput === this.defaultFilterDisplayType) ||
|
|
1394
|
+
f.descriptor.displayType === FilterDisplayTypeEnum.DirectInput), ...(ngDevMode ? [{ debugName: "directInputMetadata" }] : []));
|
|
1395
|
+
this.overlayFormFilters = computed(() => {
|
|
1396
|
+
return this.getInitialFilters(this.tableData.filterStates(), this.overlayFormMetadata());
|
|
1397
|
+
}, ...(ngDevMode ? [{ debugName: "overlayFormFilters" }] : []));
|
|
1398
|
+
this.showOverlayFilterFormButton = computed(() => this.overlayFormMetadata().length > 0, ...(ngDevMode ? [{ debugName: "showOverlayFilterFormButton" }] : []));
|
|
1399
|
+
this.activeFilters = computed(() => {
|
|
1400
|
+
const filterEntry = this.overlayFormFilters();
|
|
1401
|
+
return this.overlayFormMetadata()
|
|
1402
|
+
.filter(d => {
|
|
1403
|
+
const filter = filterEntry[d.descriptor.property];
|
|
1404
|
+
return (filter &&
|
|
1405
|
+
filter.matchMode !== undefined &&
|
|
1406
|
+
filter.displayMatchMode !== undefined &&
|
|
1407
|
+
(filter.matchMode === FilterMatchMode.Exists ||
|
|
1408
|
+
filter.matchMode === FilterMatchMode.DoesNotExist ||
|
|
1409
|
+
(filter.value !== undefined && filter.displayValue !== undefined)));
|
|
1410
|
+
})
|
|
1411
|
+
.map(d => filterEntry[d.descriptor.property]);
|
|
1412
|
+
}, ...(ngDevMode ? [{ debugName: "activeFilters" }] : []));
|
|
1413
|
+
this.activeFilterProperties = computed(() => this.activeFilters().map(f => f.config.descriptor.property), ...(ngDevMode ? [{ debugName: "activeFilterProperties" }] : []));
|
|
1414
|
+
this.filterEdit = signal(undefined, ...(ngDevMode ? [{ debugName: "filterEdit" }] : []));
|
|
1415
|
+
this.unsetRequiredFilters = computed(() => {
|
|
1416
|
+
const activeFilters = this.activeFilters().map(el => el.config.descriptor.property);
|
|
1417
|
+
return this.overlayFormMetadata()
|
|
1418
|
+
.filter(el => el.descriptor.isRequired && !activeFilters.includes(el.descriptor.property))
|
|
1419
|
+
.map(el => {
|
|
1420
|
+
return {
|
|
1421
|
+
matchMode: el.defaultMatchMode,
|
|
1422
|
+
displayMatchMode: el.defaultMatchMode,
|
|
1423
|
+
config: el
|
|
1424
|
+
};
|
|
1425
|
+
});
|
|
1426
|
+
}, ...(ngDevMode ? [{ debugName: "unsetRequiredFilters" }] : []));
|
|
1427
|
+
this.allActiveFiltersDisabled = computed(() => this.activeFilters().filter(f => f.disabled).length === this.activeFilters().length, ...(ngDevMode ? [{ debugName: "allActiveFiltersDisabled" }] : []));
|
|
1428
|
+
this.addFilterShortcutText = isMac() ? '⌘ + /' : 'Ctrl + /';
|
|
1429
|
+
// global search model
|
|
1430
|
+
this.searchValue = computed(() => this.search()?.value, ...(ngDevMode ? [{ debugName: "searchValue" }] : []));
|
|
1431
|
+
this.searchCaseSensitive = computed(() => this.search()?.caseSensitive, ...(ngDevMode ? [{ debugName: "searchCaseSensitive" }] : []));
|
|
1432
|
+
this.searchWordLimitMaxError = signal(false, ...(ngDevMode ? [{ debugName: "searchWordLimitMaxError" }] : []));
|
|
1433
|
+
this.searchWordLimitMaxCmp = computed(() => {
|
|
1434
|
+
const inputLimit = this.searchLimitWordMax();
|
|
1435
|
+
if (inputLimit !== undefined) {
|
|
1436
|
+
return inputLimit;
|
|
1437
|
+
}
|
|
1438
|
+
return this.tableConfig?.searchLimitMaxWords !== undefined ? this.tableConfig?.searchLimitMaxWords : TableHeaderWithFiltersComponent.SEARCH_WORD_LIMIT_MAX;
|
|
1439
|
+
}, ...(ngDevMode ? [{ debugName: "searchWordLimitMaxCmp" }] : []));
|
|
1440
|
+
this.searchValueSubject = new BehaviorSubject(undefined);
|
|
1441
|
+
this.searchCaseSensitiveSubject = new BehaviorSubject(undefined);
|
|
1442
|
+
// UI utilities
|
|
1443
|
+
this.clickedOnFilterEvent = undefined;
|
|
1444
|
+
this.filterSplitButton = viewChild.required('filterSplitButton');
|
|
1445
|
+
this.searchInput = viewChild.required('searchInput');
|
|
1446
|
+
this.overlaySelectors = [
|
|
1447
|
+
'.p-dialog',
|
|
1448
|
+
'.p-overlaypanel',
|
|
1449
|
+
'.p-popover',
|
|
1450
|
+
'.p-confirm-popup',
|
|
1451
|
+
'.p-confirm-dialog',
|
|
1452
|
+
'.p-drawer',
|
|
1453
|
+
'.p-menu.p-menu-overlay',
|
|
1454
|
+
'.p-tieredmenu-overlay'
|
|
1455
|
+
];
|
|
1456
|
+
this.FilterTypeEnum = FilterTypeEnum;
|
|
1457
|
+
combineLatest([this.searchValueSubject.pipe(debounceTime(500), distinctUntilChanged()), this.searchCaseSensitiveSubject])
|
|
1458
|
+
// NOTE: skip is used to ignore propagating the initial value of the subjects
|
|
1459
|
+
.pipe(skip(1), takeUntilDestroyed())
|
|
1460
|
+
.subscribe(([value, caseSensitive]) => {
|
|
1461
|
+
this.updateSearch(value == null ? (this.search()?.value ?? '') : value, caseSensitive == null ? (this.search()?.caseSensitive ?? undefined) : caseSensitive);
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
onFilterFormApply(event) {
|
|
1465
|
+
const filterMetadata = this.metadata().find(d => d.descriptor.property === event.property);
|
|
1466
|
+
if (!filterMetadata) {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
const filterData = {
|
|
1470
|
+
...filterSetStateOnDisplayChange({ caseSensitive: event.caseSensitive }, event.matchMode, event.value, filterMetadata.descriptor.filterType, filterMetadata.dateConfig),
|
|
1471
|
+
config: filterMetadata
|
|
1472
|
+
};
|
|
1473
|
+
this.updateFilter(filterData);
|
|
1474
|
+
// this keeps the UI updated properly before closing the overlay
|
|
1475
|
+
this.filterEdit.set(filterData);
|
|
1476
|
+
// Resetting the form is done in the onOverlayHide callback because resetting the
|
|
1477
|
+
// values here renders empty inputs for a split second before closing the overlay
|
|
1478
|
+
this.filterOverlay().hide();
|
|
1479
|
+
}
|
|
1480
|
+
onFilterRemove(event) {
|
|
1481
|
+
this.updateFilter({
|
|
1482
|
+
...this.overlayFormFilters()[event.filter.config.descriptor.property],
|
|
1483
|
+
matchMode: undefined,
|
|
1484
|
+
displayMatchMode: undefined,
|
|
1485
|
+
value: undefined,
|
|
1486
|
+
displayValue: undefined,
|
|
1487
|
+
disabled: undefined
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
onFilterEdit(event) {
|
|
1491
|
+
this.onFilterAddOrEdit(event.filter, event.event);
|
|
1492
|
+
}
|
|
1493
|
+
isOverlayOpen() {
|
|
1494
|
+
return this.overlaySelectors.some(sel => !!document.querySelector(sel));
|
|
1495
|
+
}
|
|
1496
|
+
filterShortcuts(event) {
|
|
1497
|
+
// Add Filter shortcut: ctrl + / or ⌘ + /
|
|
1498
|
+
if (((!isMac() && event.ctrlKey) || (isMac() && event.metaKey)) && event.key === '/') {
|
|
1499
|
+
event.preventDefault();
|
|
1500
|
+
if (this.isOverlayOpen() && !this.filterOverlay().overlayVisible)
|
|
1501
|
+
return;
|
|
1502
|
+
this.onFilterAdd(event);
|
|
1503
|
+
}
|
|
1504
|
+
// Search shortcut: /
|
|
1505
|
+
else if (this.enableSearch() && event.key === '/') {
|
|
1506
|
+
const target = event.target;
|
|
1507
|
+
const isTyping = !!target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable);
|
|
1508
|
+
if (isTyping)
|
|
1509
|
+
return; // don’t interrupt typing
|
|
1510
|
+
event.preventDefault();
|
|
1511
|
+
if (this.isOverlayOpen())
|
|
1512
|
+
return;
|
|
1513
|
+
this.searchInput().nativeElement.focus();
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
onFilterSplitButtonShow() {
|
|
1517
|
+
this.filterMenuItems.set([
|
|
1518
|
+
{
|
|
1519
|
+
label: this.allActiveFiltersDisabled() ? this.translateService.instant('mngFilter.enableAll') : this.translateService.instant('mngFilter.disableAll'),
|
|
1520
|
+
icon: this.allActiveFiltersDisabled() ? 'pi pi-check-circle' : 'pi pi-ban',
|
|
1521
|
+
command: () => this.onFilterToggleDisableAll(),
|
|
1522
|
+
disabled: !this.activeFilters()?.length
|
|
1523
|
+
},
|
|
1524
|
+
{ separator: true },
|
|
1525
|
+
{
|
|
1526
|
+
label: this.translateService.instant('mngFilter.removeAll'),
|
|
1527
|
+
icon: 'pi pi-times',
|
|
1528
|
+
command: () => this.onFilterRemoveAll(),
|
|
1529
|
+
disabled: !this.activeFilters()?.length
|
|
1530
|
+
}
|
|
1531
|
+
]);
|
|
1532
|
+
}
|
|
1533
|
+
onFilterAdd(event) {
|
|
1534
|
+
this.onFilterAddOrEdit(undefined, event);
|
|
1535
|
+
}
|
|
1536
|
+
onFilterToggleDisabled(event) {
|
|
1537
|
+
this.updateFilter({
|
|
1538
|
+
...this.overlayFormFilters()[event.filter.config.descriptor.property],
|
|
1539
|
+
disabled: event.filter.disabled
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
onFilterToggleDisableAll() {
|
|
1543
|
+
this.tableData.updateFilters(Object.fromEntries(this.activeFilters().map(f => [f.config.descriptor.property, { ...f, disabled: !this.allActiveFiltersDisabled() }])));
|
|
1544
|
+
}
|
|
1545
|
+
onFilterRemoveAll() {
|
|
1546
|
+
this.tableData.updateFilters(Object.fromEntries(this.activeFilters().map(f => [f.config.descriptor.property, undefined])));
|
|
1547
|
+
}
|
|
1548
|
+
onSearchChange(value) {
|
|
1549
|
+
const searchWordLimitMax = this.searchWordLimitMaxCmp();
|
|
1550
|
+
if (searchWordLimitMax !== null) {
|
|
1551
|
+
const wordCount = value.split(/\s+/).filter(word => word.length > 0).length;
|
|
1552
|
+
this.searchWordLimitMaxError.set(wordCount > searchWordLimitMax);
|
|
1553
|
+
}
|
|
1554
|
+
else {
|
|
1555
|
+
this.searchWordLimitMaxError.set(false);
|
|
1556
|
+
}
|
|
1557
|
+
if (!this.searchWordLimitMaxError()) {
|
|
1558
|
+
this.searchValueSubject.next(value);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
// if inside a form prevent the default 'enter' event to submit it
|
|
1562
|
+
onSearchSubmit(event) {
|
|
1563
|
+
event.preventDefault(); // functionality still works because it's bound to change and not enter/submit.
|
|
1564
|
+
}
|
|
1565
|
+
onSearchCaseSensitiveChange(value) {
|
|
1566
|
+
this.searchCaseSensitiveSubject.next(value);
|
|
1567
|
+
}
|
|
1568
|
+
onOverlayHide() {
|
|
1569
|
+
// resetting the form is done here for a smoother animation
|
|
1570
|
+
if (this.filterFormComponent !== undefined) {
|
|
1571
|
+
this.filterFormComponent()?.resetForm();
|
|
1572
|
+
}
|
|
1573
|
+
if (this.clickedOnFilterEvent) {
|
|
1574
|
+
// show the overlay again if the user clicked another filter
|
|
1575
|
+
setTimeout(() => {
|
|
1576
|
+
this.filterEdit.set(this.clickedOnFilterEvent?.filter);
|
|
1577
|
+
const event = this.clickedOnFilterEvent?.event;
|
|
1578
|
+
if (event instanceof KeyboardEvent) {
|
|
1579
|
+
this.filterOverlay().show(event, this.filterSplitButton().el.nativeElement); // a keyboard event doesn't have a target, so we add it manually
|
|
1580
|
+
}
|
|
1581
|
+
else {
|
|
1582
|
+
this.filterOverlay().show(event);
|
|
1583
|
+
}
|
|
1584
|
+
this.clickedOnFilterEvent = undefined;
|
|
1585
|
+
}, 0);
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
else {
|
|
1589
|
+
// clean state
|
|
1590
|
+
this.filterEdit.set(undefined);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
onFilterAddOrEdit(filter, event) {
|
|
1594
|
+
// If user clicks on the same filter or add that is already open, close the overlay
|
|
1595
|
+
if (this.filterOverlay().overlayVisible && this.filterEdit()?.config.descriptor.property === filter?.config.descriptor.property) {
|
|
1596
|
+
this.filterOverlay().hide();
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
if (this.filterOverlay().overlayVisible) {
|
|
1600
|
+
// In case the user clicks another filter, 're-showing' the overlay in
|
|
1601
|
+
// the new position is done in the onOverlayHide callback
|
|
1602
|
+
this.clickedOnFilterEvent = { event, filter };
|
|
1603
|
+
this.filterOverlay().hide();
|
|
1604
|
+
}
|
|
1605
|
+
else {
|
|
1606
|
+
this.filterEdit.set(filter);
|
|
1607
|
+
// When invoked via keyboard, provide a concrete anchor element for positioning
|
|
1608
|
+
if (event instanceof KeyboardEvent) {
|
|
1609
|
+
this.filterOverlay().show(event, this.filterSplitButton().el.nativeElement); // a keyboard event doesn't have a target, so we add it manually
|
|
1610
|
+
}
|
|
1611
|
+
else {
|
|
1612
|
+
this.filterOverlay().show(event);
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
getInitialFilters(filtersInit, metadata) {
|
|
1617
|
+
const filtersResult = {};
|
|
1618
|
+
if (filtersInit) {
|
|
1619
|
+
for (const property in filtersInit) {
|
|
1620
|
+
const filterInit = filtersInit[property];
|
|
1621
|
+
const filterMetadata = metadata.find(m => m.descriptor.property === property);
|
|
1622
|
+
if (!filterMetadata) {
|
|
1623
|
+
continue;
|
|
1624
|
+
}
|
|
1625
|
+
filtersResult[property] = {
|
|
1626
|
+
...filterSetStateOnChange(filterInit, filterInit.matchMode, filterInit.value, filterMetadata.descriptor.filterType, filterMetadata.dateConfig),
|
|
1627
|
+
config: filterMetadata
|
|
1628
|
+
};
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
return filtersResult;
|
|
1632
|
+
}
|
|
1633
|
+
updateFilter(filter) {
|
|
1634
|
+
this.tableData.updateFilters({ [filter.config.descriptor.property]: filter });
|
|
1635
|
+
}
|
|
1636
|
+
updateSearch(searchQuery, caseSensitive = false) {
|
|
1637
|
+
// match mode needs to be set for inline search
|
|
1638
|
+
this.tableData.updateSearch(searchQuery != null ? { value: searchQuery, caseSensitive: caseSensitive } : undefined);
|
|
1639
|
+
}
|
|
1640
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableHeaderWithFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1641
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableHeaderWithFiltersComponent, isStandalone: true, selector: "mng-table-header-with-filters", inputs: { metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: true, transformFunction: null }, genericFilterDescriptor: { classPropertyName: "genericFilterDescriptor", publicName: "genericFilterDescriptor", isSignal: true, isRequired: false, transformFunction: null }, model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, enableSearch: { classPropertyName: "enableSearch", publicName: "enableSearch", isSignal: true, isRequired: false, transformFunction: null }, search: { classPropertyName: "search", publicName: "search", isSignal: true, isRequired: false, transformFunction: null }, searchLimitWordMax: { classPropertyName: "searchLimitWordMax", publicName: "searchLimitWordMax", isSignal: true, isRequired: false, transformFunction: null }, enableCaseSensitive: { classPropertyName: "enableCaseSensitive", publicName: "enableCaseSensitive", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:keydown": "filterShortcuts($event)" } }, queries: [{ propertyName: "templates", predicate: TableHeaderWithFiltersTemplateDirective, isSignal: true }], viewQueries: [{ propertyName: "filterOverlay", first: true, predicate: Popover, descendants: true, isSignal: true }, { propertyName: "filterFormComponent", first: true, predicate: TableFilterFormComponent, descendants: true, isSignal: true }, { propertyName: "filterSplitButton", first: true, predicate: ["filterSplitButton"], descendants: true, isSignal: true }, { propertyName: "searchInput", first: true, predicate: ["searchInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"flex items-center grow flex-wrap\">\n @if (titleTemplate()) {\n <ng-container *ngTemplateOutlet=\"titleTemplate()\"></ng-container>\n }\n @if (showOverlayFilterFormButton()) {\n <p-splitbutton\n #filterSplitButton\n [label]=\"'mngFilter.titleAdd' | translate\"\n [severity]=\"'secondary'\"\n (onClick)=\"onFilterAdd($event)\"\n [class]=\"'mng-filter-add-button mr-2' + (titleTemplate() ? ' ml-3' : '')\"\n (onMenuShow)=\"onFilterSplitButtonShow()\"\n showDelay=\"500\"\n [pTooltip]=\"('mngFilter.titleAdd' | translate) + ' ( ' + addFilterShortcutText + ' )'\"\n icon=\"pi pi-filter\"\n [model]=\"filterMenuItems()\">\n </p-splitbutton>\n }\n @if (enableSearch()) {\n <div\n class=\"mng-search mr-3\"\n [ngClass]=\"{'ml-3': !showOverlayFilterFormButton() && titleTemplate()}\"\n showDelay=\"500\"\n [pTooltip]=\"('mngFilter.search.input' | translate) + ' ( / )'\">\n <span class=\"p-input-icon-left w-full\">\n <p-iconfield>\n <p-inputicon class=\"pi pi-search\" />\n <input\n #searchInput\n [ngModel]=\"searchValue()\"\n (ngModelChange)=\"onSearchChange($event)\"\n (keydown.enter)=\"onSearchSubmit($event)\"\n name=\"globalSearch\"\n type=\"text\"\n pInputText\n class=\"search-input w-full\"\n [ngClass]=\"{'ng-invalid': searchWordLimitMaxError()}\"\n [attr.placeholder]=\"'mngFilter.search.input' | translate\"\n [placeholder]=\"'mngFilter.search.input' | translate\" />\n <span class=\"search-shortcut-hint\">/</span>\n </p-iconfield>\n @if (enableCaseSensitive()) {\n <span class=\"toggle-button-input\">\n <p-toggleButton\n styleClass=\"ml-1 p-1 p-button-sm\"\n [ngModel]=\"searchCaseSensitive()\"\n (ngModelChange)=\"onSearchCaseSensitiveChange($event)\"\n onLabel=\"Aa\"\n offLabel=\"Aa\" />\n </span>\n }\n </span>\n @if (searchWordLimitMaxError()) {\n <small class=\"p-error block\">\n {{ 'mngFilter.search.maxWordsExceededMessage' | translate }}\n </small>\n }\n </div>\n }\n @if (directInputMetadata().length > 0) {\n <div class=\"mng-direct-input-filters flex flex-wrap items-center my-1\">\n @for (metadata of directInputMetadata(); track metadata.descriptor.property) {\n @if (metadata.descriptor.filterType !== FilterTypeEnum.Component) {\n @defer (on idle) {\n <mng-table-filter [config]=\"metadata\" [model]=\"model()\" [showFilterIcon]=\"true\" [showTitleAsPlaceholder]=\"true\" class=\"mx-1 my-1\" />\n }\n } @else if (metadata.descriptor.customComponentType) {\n <ng-container [mngComponent]=\"metadata.descriptor.customComponentType\" [inputs]=\"{descriptor: metadata.descriptor}\"></ng-container>\n }\n }\n </div>\n }\n @if (titleRowRightTemplate()) {\n <ng-container *ngTemplateOutlet=\"titleRowRightTemplate()\"></ng-container>\n }\n</div>\n@if (activeFilters().length > 0 || unsetRequiredFilters().length > 0) {\n <div class=\"flex items-center flex-wrap mt-2\">\n @for (filter of unsetRequiredFilters(); track filter.config.descriptor.property) {\n @defer (on viewport) {\n <mng-table-filter-active-tag\n [model]=\"model()\"\n [filter]=\"filter\"\n (edit)=\"onFilterEdit($event)\"\n (remove)=\"onFilterRemove($event)\"\n (toggleDisabled)=\"onFilterToggleDisabled($event)\" />\n } @placeholder {\n <p-skeleton width=\"10rem\" height=\"2rem\"></p-skeleton>\n }\n }\n @for (filter of activeFilters(); track filter.config.descriptor.property) {\n @defer (on viewport) {\n <mng-table-filter-active-tag\n [model]=\"model()\"\n [filter]=\"filter\"\n (edit)=\"onFilterEdit($event)\"\n (remove)=\"onFilterRemove($event)\"\n (toggleDisabled)=\"onFilterToggleDisabled($event)\" />\n } @placeholder {\n <p-skeleton width=\"10rem\" height=\"2rem\"></p-skeleton>\n }\n }\n </div>\n}\n<p-popover #op showCloseIcon=\"true\" (onHide)=\"onOverlayHide()\" appendTo=\"body\">\n @defer (on viewport) {\n <mng-table-filter-form\n [model]=\"model()\"\n [metadata]=\"overlayFormMetadata()\"\n [genericDescriptor]=\"genericFilterDescriptor()\"\n [filter]=\"filterEdit()\"\n [disabledProperties]=\"activeFilterProperties()\"\n [propertySearch]=\"genericFilterDescriptor()?.propertySearch\"\n [overlay]=\"op\"\n [enableCaseSensitive]=\"enableCaseSensitive()\"\n (apply)=\"onFilterFormApply($event)\" />\n } @placeholder {\n <p-skeleton width=\"20rem\" height=\"3rem\"></p-skeleton>\n }\n</p-popover>\n", styles: [".toggle-button-input{position:absolute;right:.35rem;top:50%;transform:translateY(-50%)}.mng-search{min-width:20rem}.search-shortcut-hint{position:absolute;right:1rem;top:50%;transform:translateY(-50%);font-size:1.1rem;pointer-events:none;opacity:.5;transition:opacity .15s}.search-input:not(:placeholder-shown)~.search-shortcut-hint,.search-input:focus~.search-shortcut-hint{opacity:0;pointer-events:none}\n"], dependencies: [{ kind: "ngmodule", type: TagModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ToggleButton, selector: "p-toggleButton, p-togglebutton, p-toggle-button", inputs: ["onLabel", "offLabel", "onIcon", "offIcon", "ariaLabel", "ariaLabelledBy", "styleClass", "inputId", "tabindex", "iconPos", "autofocus", "size", "allowEmpty", "fluid"], outputs: ["onChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.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: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "component", type: InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "component", type: Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "directive", type: ComponentDirective, selector: "[mngComponent]", inputs: ["mngComponent", "injectionToken", "inputs", "attachToHost", "parentInjector"], outputs: ["instanceCreated"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "component", type: SplitButton, selector: "p-splitbutton, p-splitButton, p-split-button", inputs: ["model", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "icon", "iconPos", "label", "tooltip", "tooltipOptions", "styleClass", "menuStyle", "menuStyleClass", "dropdownIcon", "appendTo", "dir", "expandAriaLabel", "showTransitionOptions", "hideTransitionOptions", "buttonProps", "menuButtonProps", "autofocus", "disabled", "tabindex", "menuButtonDisabled", "buttonDisabled"], outputs: ["onClick", "onMenuHide", "onMenuShow", "onDropdownClick"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, deferBlockDependencies: [() => [Promise.resolve().then(function () { return filter_component; }).then(m => m.TableFilterComponent)], () => [Promise.resolve().then(function () { return filterActiveTag_component; }).then(m => m.TableFilterActiveTagComponent)], () => [Promise.resolve().then(function () { return filterActiveTag_component; }).then(m => m.TableFilterActiveTagComponent)], () => [TableFilterFormComponent]] }); }
|
|
1642
|
+
}
|
|
1643
|
+
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "20.3.15", ngImport: i0, type: TableHeaderWithFiltersComponent, resolveDeferredDeps: () => [Promise.resolve().then(function () { return filter_component; }).then(m => m.TableFilterComponent), Promise.resolve().then(function () { return filterActiveTag_component; }).then(m => m.TableFilterActiveTagComponent)], resolveMetadata: (TableFilterComponent, TableFilterActiveTagComponent) => ({ decorators: [{
|
|
1644
|
+
type: Component,
|
|
1645
|
+
args: [{ selector: 'mng-table-header-with-filters', imports: [
|
|
1646
|
+
TranslatePipe,
|
|
1647
|
+
TagModule,
|
|
1648
|
+
TableFilterFormComponent,
|
|
1649
|
+
TableFilterActiveTagComponent,
|
|
1650
|
+
NgTemplateOutlet,
|
|
1651
|
+
InputText,
|
|
1652
|
+
NgClass,
|
|
1653
|
+
ToggleButton,
|
|
1654
|
+
FormsModule,
|
|
1655
|
+
IconField,
|
|
1656
|
+
InputIcon,
|
|
1657
|
+
Popover,
|
|
1658
|
+
TableFilterComponent,
|
|
1659
|
+
ComponentDirective,
|
|
1660
|
+
Skeleton,
|
|
1661
|
+
SplitButton,
|
|
1662
|
+
Tooltip
|
|
1663
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex items-center grow flex-wrap\">\n @if (titleTemplate()) {\n <ng-container *ngTemplateOutlet=\"titleTemplate()\"></ng-container>\n }\n @if (showOverlayFilterFormButton()) {\n <p-splitbutton\n #filterSplitButton\n [label]=\"'mngFilter.titleAdd' | translate\"\n [severity]=\"'secondary'\"\n (onClick)=\"onFilterAdd($event)\"\n [class]=\"'mng-filter-add-button mr-2' + (titleTemplate() ? ' ml-3' : '')\"\n (onMenuShow)=\"onFilterSplitButtonShow()\"\n showDelay=\"500\"\n [pTooltip]=\"('mngFilter.titleAdd' | translate) + ' ( ' + addFilterShortcutText + ' )'\"\n icon=\"pi pi-filter\"\n [model]=\"filterMenuItems()\">\n </p-splitbutton>\n }\n @if (enableSearch()) {\n <div\n class=\"mng-search mr-3\"\n [ngClass]=\"{'ml-3': !showOverlayFilterFormButton() && titleTemplate()}\"\n showDelay=\"500\"\n [pTooltip]=\"('mngFilter.search.input' | translate) + ' ( / )'\">\n <span class=\"p-input-icon-left w-full\">\n <p-iconfield>\n <p-inputicon class=\"pi pi-search\" />\n <input\n #searchInput\n [ngModel]=\"searchValue()\"\n (ngModelChange)=\"onSearchChange($event)\"\n (keydown.enter)=\"onSearchSubmit($event)\"\n name=\"globalSearch\"\n type=\"text\"\n pInputText\n class=\"search-input w-full\"\n [ngClass]=\"{'ng-invalid': searchWordLimitMaxError()}\"\n [attr.placeholder]=\"'mngFilter.search.input' | translate\"\n [placeholder]=\"'mngFilter.search.input' | translate\" />\n <span class=\"search-shortcut-hint\">/</span>\n </p-iconfield>\n @if (enableCaseSensitive()) {\n <span class=\"toggle-button-input\">\n <p-toggleButton\n styleClass=\"ml-1 p-1 p-button-sm\"\n [ngModel]=\"searchCaseSensitive()\"\n (ngModelChange)=\"onSearchCaseSensitiveChange($event)\"\n onLabel=\"Aa\"\n offLabel=\"Aa\" />\n </span>\n }\n </span>\n @if (searchWordLimitMaxError()) {\n <small class=\"p-error block\">\n {{ 'mngFilter.search.maxWordsExceededMessage' | translate }}\n </small>\n }\n </div>\n }\n @if (directInputMetadata().length > 0) {\n <div class=\"mng-direct-input-filters flex flex-wrap items-center my-1\">\n @for (metadata of directInputMetadata(); track metadata.descriptor.property) {\n @if (metadata.descriptor.filterType !== FilterTypeEnum.Component) {\n @defer (on idle) {\n <mng-table-filter [config]=\"metadata\" [model]=\"model()\" [showFilterIcon]=\"true\" [showTitleAsPlaceholder]=\"true\" class=\"mx-1 my-1\" />\n }\n } @else if (metadata.descriptor.customComponentType) {\n <ng-container [mngComponent]=\"metadata.descriptor.customComponentType\" [inputs]=\"{descriptor: metadata.descriptor}\"></ng-container>\n }\n }\n </div>\n }\n @if (titleRowRightTemplate()) {\n <ng-container *ngTemplateOutlet=\"titleRowRightTemplate()\"></ng-container>\n }\n</div>\n@if (activeFilters().length > 0 || unsetRequiredFilters().length > 0) {\n <div class=\"flex items-center flex-wrap mt-2\">\n @for (filter of unsetRequiredFilters(); track filter.config.descriptor.property) {\n @defer (on viewport) {\n <mng-table-filter-active-tag\n [model]=\"model()\"\n [filter]=\"filter\"\n (edit)=\"onFilterEdit($event)\"\n (remove)=\"onFilterRemove($event)\"\n (toggleDisabled)=\"onFilterToggleDisabled($event)\" />\n } @placeholder {\n <p-skeleton width=\"10rem\" height=\"2rem\"></p-skeleton>\n }\n }\n @for (filter of activeFilters(); track filter.config.descriptor.property) {\n @defer (on viewport) {\n <mng-table-filter-active-tag\n [model]=\"model()\"\n [filter]=\"filter\"\n (edit)=\"onFilterEdit($event)\"\n (remove)=\"onFilterRemove($event)\"\n (toggleDisabled)=\"onFilterToggleDisabled($event)\" />\n } @placeholder {\n <p-skeleton width=\"10rem\" height=\"2rem\"></p-skeleton>\n }\n }\n </div>\n}\n<p-popover #op showCloseIcon=\"true\" (onHide)=\"onOverlayHide()\" appendTo=\"body\">\n @defer (on viewport) {\n <mng-table-filter-form\n [model]=\"model()\"\n [metadata]=\"overlayFormMetadata()\"\n [genericDescriptor]=\"genericFilterDescriptor()\"\n [filter]=\"filterEdit()\"\n [disabledProperties]=\"activeFilterProperties()\"\n [propertySearch]=\"genericFilterDescriptor()?.propertySearch\"\n [overlay]=\"op\"\n [enableCaseSensitive]=\"enableCaseSensitive()\"\n (apply)=\"onFilterFormApply($event)\" />\n } @placeholder {\n <p-skeleton width=\"20rem\" height=\"3rem\"></p-skeleton>\n }\n</p-popover>\n", styles: [".toggle-button-input{position:absolute;right:.35rem;top:50%;transform:translateY(-50%)}.mng-search{min-width:20rem}.search-shortcut-hint{position:absolute;right:1rem;top:50%;transform:translateY(-50%);font-size:1.1rem;pointer-events:none;opacity:.5;transition:opacity .15s}.search-input:not(:placeholder-shown)~.search-shortcut-hint,.search-input:focus~.search-shortcut-hint{opacity:0;pointer-events:none}\n"] }]
|
|
1664
|
+
}], ctorParameters: () => [], propDecorators: { metadata: [{ type: i0.Input, args: [{ isSignal: true, alias: "metadata", required: true }] }], genericFilterDescriptor: [{ type: i0.Input, args: [{ isSignal: true, alias: "genericFilterDescriptor", required: false }] }], model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: true }] }], enableSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableSearch", required: false }] }], search: [{ type: i0.Input, args: [{ isSignal: true, alias: "search", required: false }] }], searchLimitWordMax: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchLimitWordMax", required: false }] }], enableCaseSensitive: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableCaseSensitive", required: false }] }], filterOverlay: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Popover), { isSignal: true }] }], filterFormComponent: [{ type: i0.ViewChild, args: [i0.forwardRef(() => TableFilterFormComponent), { isSignal: true }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TableHeaderWithFiltersTemplateDirective), { isSignal: true }] }], filterSplitButton: [{ type: i0.ViewChild, args: ['filterSplitButton', { isSignal: true }] }], searchInput: [{ type: i0.ViewChild, args: ['searchInput', { isSignal: true }] }], filterShortcuts: [{
|
|
1665
|
+
type: HostListener,
|
|
1666
|
+
args: ['window:keydown', ['$event']]
|
|
1667
|
+
}] } }) });
|
|
1668
|
+
|
|
1669
|
+
/**
|
|
1670
|
+
* Generates and displays a notification for a table-related error with localized error messages and details.
|
|
1671
|
+
*
|
|
1672
|
+
* @param {TranslateService} translate - The service used to handle localization and translations.
|
|
1673
|
+
* @param {MessageService} messageService - The service used to manage and display messages.
|
|
1674
|
+
* @param {TableDescriptorInst<any>} table - The table descriptor containing table-specific information and model data.
|
|
1675
|
+
* @param {Error} error - The error object providing details about the error that occurred.
|
|
1676
|
+
* @return {Message | null} The generated message object for the error notification or null if no notification was created.
|
|
1677
|
+
*/
|
|
1678
|
+
function tableNotificationError(translate, messageService, table, error) {
|
|
1679
|
+
const params = {
|
|
1680
|
+
errorMessage: getI18nForError(translate, error) ?? error.message,
|
|
1681
|
+
...getI18nErrorParams(error)
|
|
1682
|
+
};
|
|
1683
|
+
const tableErrorTitle = getI18nForModel(translate, table.model, 'table.error.title', { fallbackKey: 'general.error', params }) ?? undefined;
|
|
1684
|
+
const tableErrorMessage = getI18nForModel(translate, table.model, 'table.error.message', { fallbackKey: 'general.errorMessage', params }) ?? undefined;
|
|
1685
|
+
return toastMessage(tableErrorMessage ?? error.message, 'error', { messageService: messageService, title: tableErrorTitle, icon: 'pi-exclamation-triangle' });
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
class LocaleDefaultRowClassPipe {
|
|
1689
|
+
constructor() {
|
|
1690
|
+
this.injector = inject(Injector);
|
|
1691
|
+
}
|
|
1692
|
+
transform(value, descriptor, item) {
|
|
1693
|
+
if (descriptor?.isLocalized) {
|
|
1694
|
+
if (item[descriptor.localizationLocaleProperty] === this.injector.get(CommonsService).getDefaultLocale()) {
|
|
1695
|
+
return value + ' mng-table-row-localization-default-locale';
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return value ?? '';
|
|
1699
|
+
}
|
|
1700
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: LocaleDefaultRowClassPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
1701
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: LocaleDefaultRowClassPipe, isStandalone: true, name: "mngLocaleDefaultRowClass" }); }
|
|
1702
|
+
}
|
|
1703
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: LocaleDefaultRowClassPipe, decorators: [{
|
|
1704
|
+
type: Pipe,
|
|
1705
|
+
args: [{
|
|
1706
|
+
name: 'mngLocaleDefaultRowClass',
|
|
1707
|
+
pure: true
|
|
1708
|
+
}]
|
|
1709
|
+
}] });
|
|
1710
|
+
|
|
1711
|
+
class TableFilterClassPipe {
|
|
1712
|
+
transform(value, filter, isEnabled) {
|
|
1713
|
+
const strValue = typeof value === 'string' ? value : '';
|
|
1714
|
+
if (isEnabled && filter?.filterType !== undefined) {
|
|
1715
|
+
return `${strValue} mng-filter-${FilterTypeEnum[filter.filterType].toLowerCase()}`;
|
|
1716
|
+
}
|
|
1717
|
+
else {
|
|
1718
|
+
return strValue;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterClassPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
1722
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: TableFilterClassPipe, isStandalone: true, name: "mngTableFilterClass" }); }
|
|
1723
|
+
}
|
|
1724
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableFilterClassPipe, decorators: [{
|
|
1725
|
+
type: Pipe,
|
|
1726
|
+
args: [{
|
|
1727
|
+
pure: true,
|
|
1728
|
+
name: 'mngTableFilterClass'
|
|
1729
|
+
}]
|
|
1730
|
+
}] });
|
|
1731
|
+
|
|
1732
|
+
function tableCreateFilterMeta(paramsWithDefaults) {
|
|
1733
|
+
const primeFilterMeta = {};
|
|
1734
|
+
// if any filter is present, no default filters should be applied!
|
|
1735
|
+
if (paramsWithDefaults?.filters) {
|
|
1736
|
+
Object.entries(paramsWithDefaults.filters).forEach(([key, value]) => {
|
|
1737
|
+
primeFilterMeta[key] = {
|
|
1738
|
+
value: value?.value,
|
|
1739
|
+
matchMode: value?.matchMode,
|
|
1740
|
+
caseSensitive: value?.caseSensitive,
|
|
1741
|
+
disabled: value?.disabled
|
|
1742
|
+
};
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
return primeFilterMeta;
|
|
1746
|
+
}
|
|
1747
|
+
function tableCreateSortMeta(paramsWithDefaults) {
|
|
1748
|
+
if (paramsWithDefaults?.sort !== undefined && Array.isArray(paramsWithDefaults?.sort) && paramsWithDefaults?.sort.length > 0) {
|
|
1749
|
+
return paramsWithDefaults?.sort.map(s => ({
|
|
1750
|
+
field: s.property,
|
|
1751
|
+
order: s.ascending ? 1 : -1
|
|
1752
|
+
}));
|
|
1753
|
+
}
|
|
1754
|
+
return undefined;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
class TableMetadataService {
|
|
1758
|
+
static { this.cmpTypeName = 'TableComponent'; }
|
|
1759
|
+
#injector;
|
|
1760
|
+
#primeConfig;
|
|
1761
|
+
#translationObserver;
|
|
1762
|
+
// signal sources
|
|
1763
|
+
#signalSources;
|
|
1764
|
+
#descriptor;
|
|
1765
|
+
#updateDescriptorFromSourceEffect;
|
|
1766
|
+
#genericFilters;
|
|
1767
|
+
// search
|
|
1768
|
+
#searchFieldsFromSignalSource;
|
|
1769
|
+
#searchFields;
|
|
1770
|
+
#searchFieldsEffect;
|
|
1771
|
+
constructor() {
|
|
1772
|
+
this.#injector = inject(Injector);
|
|
1773
|
+
this.#primeConfig = inject(PrimeNG);
|
|
1774
|
+
this.moduleConfig = inject(COMMONS_MODULE_CONFIG_IT, { optional: true });
|
|
1775
|
+
this.tableModuleConfig = inject(COMMONS_TABLE_FEATURE_CONFIG_IT, { optional: true });
|
|
1776
|
+
this.serializationCfg = {};
|
|
1777
|
+
this.#translationObserver = toSignal(this.#primeConfig.translationObserver);
|
|
1778
|
+
this.defaultFilterDisplayType = this.tableModuleConfig?.filterDisplayType ?? FilterDisplayTypeEnum.Column;
|
|
1779
|
+
// signal sources
|
|
1780
|
+
this.#signalSources = signal({}, ...(ngDevMode ? [{ debugName: "#signalSources" }] : []));
|
|
1781
|
+
// descriptors
|
|
1782
|
+
this.descriptorFromSource = computed(() => this.#signalSources().descriptor?.(), ...(ngDevMode ? [{ debugName: "descriptorFromSource" }] : []));
|
|
1783
|
+
this.#descriptor = signal(tableDescriptor(), ...(ngDevMode ? [{ debugName: "#descriptor" }] : []));
|
|
1784
|
+
this.descriptor = this.#descriptor.asReadonly();
|
|
1785
|
+
this.#updateDescriptorFromSourceEffect = effectWithDeps([this.descriptorFromSource], ([d]) => {
|
|
1786
|
+
if (d != null) {
|
|
1787
|
+
this.#descriptor.set(d);
|
|
1788
|
+
}
|
|
1789
|
+
});
|
|
1790
|
+
// pagination
|
|
1791
|
+
this.rowsPerPageOptions = computed(() => {
|
|
1792
|
+
const descriptor = this.descriptor();
|
|
1793
|
+
if (Array.isArray(descriptor.rowsPerPageOptions) && descriptor.rowsPerPageOptions.length > 0) {
|
|
1794
|
+
return descriptor.rowsPerPageOptions;
|
|
1795
|
+
}
|
|
1796
|
+
else {
|
|
1797
|
+
return [25, 50, 100];
|
|
1798
|
+
}
|
|
1799
|
+
}, ...(ngDevMode ? [{ debugName: "rowsPerPageOptions" }] : []));
|
|
1800
|
+
// filters
|
|
1801
|
+
this.filterDescriptors = computed(() => this.descriptor().filters, ...(ngDevMode ? [{ debugName: "filterDescriptors" }] : []));
|
|
1802
|
+
this.filters = computed(() => {
|
|
1803
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1804
|
+
const observer = this.#translationObserver(); // need this one to track language changes
|
|
1805
|
+
return this.filterDescriptors().map(d => this.mapFilterDescriptorToMetadata(d));
|
|
1806
|
+
}, ...(ngDevMode ? [{ debugName: "filters" }] : []));
|
|
1807
|
+
this.genericFilterDescriptor = computed(() => this.descriptor().genericFilter, ...(ngDevMode ? [{ debugName: "genericFilterDescriptor" }] : []));
|
|
1808
|
+
this.#genericFilters = signal([], ...(ngDevMode ? [{ debugName: "#genericFilters" }] : []));
|
|
1809
|
+
this.genericFilters = this.#genericFilters.asReadonly();
|
|
1810
|
+
// search
|
|
1811
|
+
this.#searchFieldsFromSignalSource = computed(() => this.#signalSources().searchFields?.(), ...(ngDevMode ? [{ debugName: "#searchFieldsFromSignalSource" }] : []));
|
|
1812
|
+
this.#searchFields = signal([], ...(ngDevMode ? [{ debugName: "#searchFields" }] : []));
|
|
1813
|
+
this.searchFields = this.#searchFields.asReadonly();
|
|
1814
|
+
this.#searchFieldsEffect = effectWithDeps([this.descriptor, this.#searchFieldsFromSignalSource], ([descriptor, searchFieldsFromSignalSource]) => {
|
|
1815
|
+
this.#searchFields.set(searchFieldsFromSignalSource ?? (descriptor.search && descriptor.searchFields ? descriptor.searchFields : this.descriptor().columns.map(c => c.property)));
|
|
1816
|
+
});
|
|
1817
|
+
// params
|
|
1818
|
+
this.defaultParams = computed(() => {
|
|
1819
|
+
const params = {
|
|
1820
|
+
offset: 0,
|
|
1821
|
+
limit: this.rowsPerPageOptions()[0],
|
|
1822
|
+
sort: this.descriptor()
|
|
1823
|
+
.sorts.filter(s => s.defaultIsEnabled)
|
|
1824
|
+
.sort((s1, s2) => (s1.defaultOrder ?? 1000) - (s2.defaultOrder ?? 1000))
|
|
1825
|
+
.map(s => ({
|
|
1826
|
+
property: s.property,
|
|
1827
|
+
ascending: s.defaultIsAscending
|
|
1828
|
+
})),
|
|
1829
|
+
filters: {}
|
|
1830
|
+
};
|
|
1831
|
+
this.filters()
|
|
1832
|
+
.filter(f => f.descriptor.hasDefaultValue)
|
|
1833
|
+
.forEach(f => {
|
|
1834
|
+
params.filters[f.descriptor.property] = {
|
|
1835
|
+
value: f.descriptor.defaultValue,
|
|
1836
|
+
matchMode: f.defaultMatchMode
|
|
1837
|
+
};
|
|
1838
|
+
});
|
|
1839
|
+
return params;
|
|
1840
|
+
}, ...(ngDevMode ? [{ debugName: "defaultParams" }] : []));
|
|
1841
|
+
filterApplySerializationConfigToCmp(this.moduleConfig, this.serializationCfg);
|
|
1842
|
+
combineLatest([toObservable(this.genericFilterDescriptor), toObservable(this.#translationObserver)])
|
|
1843
|
+
.pipe(switchMap(([genericFilterDescriptor]) => {
|
|
1844
|
+
if (genericFilterDescriptor) {
|
|
1845
|
+
const dataProvider = this.genericFilterDescriptor()?.propertyLookup;
|
|
1846
|
+
const genericFilterService = dataProvider?.serviceType ? this.#injector.get(dataProvider.serviceType) : null;
|
|
1847
|
+
// fetch filterable properties
|
|
1848
|
+
return toObservable$1(genericFilterDescriptor.propertyLookup.lookup({}, genericFilterService));
|
|
1849
|
+
}
|
|
1850
|
+
return of([]);
|
|
1851
|
+
}), takeUntilDestroyed())
|
|
1852
|
+
.subscribe({
|
|
1853
|
+
next: genericFilters => {
|
|
1854
|
+
// set descriptors from generic filter data
|
|
1855
|
+
this.#genericFilters.set(createFilterDescriptorsFromGeneric(genericFilters, this.genericFilterDescriptor()?.valueLookup).map(d => this.mapFilterDescriptorToMetadata(d)));
|
|
1856
|
+
}
|
|
1857
|
+
});
|
|
1858
|
+
}
|
|
1859
|
+
setSignalSources(descriptor, searchFields) {
|
|
1860
|
+
this.#signalSources.set({ descriptor, searchFields });
|
|
1861
|
+
}
|
|
1862
|
+
setDescriptor(descriptor) {
|
|
1863
|
+
if (this.descriptorFromSource() instanceof TableDynamicDescriptorInst) {
|
|
1864
|
+
this.#descriptor.set(descriptor);
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
mapFilterDescriptorToMetadata(descriptor) {
|
|
1868
|
+
const matchModes = filterGenerateMatchModeOptions(this.#primeConfig, descriptor, this.serializationCfg);
|
|
1869
|
+
return {
|
|
1870
|
+
descriptor: descriptor,
|
|
1871
|
+
matchModes: matchModes,
|
|
1872
|
+
defaultMatchMode: filterGetDefaultMatchMode(descriptor, matchModes),
|
|
1873
|
+
dateConfig: filterGetDateConfig(descriptor, this.serializationCfg),
|
|
1874
|
+
numberConfig: filterGetNumberConfig(descriptor)
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1877
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableMetadataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1878
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableMetadataService }); }
|
|
1879
|
+
}
|
|
1880
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableMetadataService, decorators: [{
|
|
1881
|
+
type: Injectable
|
|
1882
|
+
}], ctorParameters: () => [] });
|
|
1883
|
+
|
|
1884
|
+
class TableDataService extends ADataListService {
|
|
1885
|
+
#injector;
|
|
1886
|
+
#destroyRef;
|
|
1887
|
+
#commons;
|
|
1888
|
+
#metadata;
|
|
1889
|
+
#primeTable;
|
|
1890
|
+
// signal sources
|
|
1891
|
+
#dataSources;
|
|
1892
|
+
// data sources
|
|
1893
|
+
#manualLoading;
|
|
1894
|
+
// results that are set directly via input and are not result of a asynchronous operation (aka data provider)
|
|
1895
|
+
#synchronousResult;
|
|
1896
|
+
#dataProvider;
|
|
1897
|
+
#dataProviderService;
|
|
1898
|
+
#synchronousResultEffect;
|
|
1899
|
+
#synchronousLoadingEffect;
|
|
1900
|
+
#manualLoadingEffect;
|
|
1901
|
+
#dataProviderSubscription;
|
|
1902
|
+
// pagination
|
|
1903
|
+
#params;
|
|
1904
|
+
#sortStates;
|
|
1905
|
+
#filterStates;
|
|
1906
|
+
#isSortAndFilterMetaInitialized;
|
|
1907
|
+
#defaultParamsEffect;
|
|
1908
|
+
#isSearchMetaInitialized;
|
|
1909
|
+
#searchState;
|
|
1910
|
+
// data
|
|
1911
|
+
#data;
|
|
1912
|
+
#count;
|
|
1913
|
+
#loading;
|
|
1914
|
+
constructor() {
|
|
1915
|
+
super();
|
|
1916
|
+
this.#injector = inject(Injector);
|
|
1917
|
+
this.#destroyRef = inject(DestroyRef);
|
|
1918
|
+
this.#commons = inject(CommonsService);
|
|
1919
|
+
this.#metadata = inject(TableMetadataService);
|
|
1920
|
+
// signal sources
|
|
1921
|
+
this.#dataSources = signal({}, ...(ngDevMode ? [{ debugName: "#dataSources" }] : []));
|
|
1922
|
+
// data sources
|
|
1923
|
+
this.#manualLoading = computed(() => this.#dataSources()?.manualLoading?.(), ...(ngDevMode ? [{ debugName: "#manualLoading" }] : []));
|
|
1924
|
+
// results that are set directly via input and are not result of a asynchronous operation (aka data provider)
|
|
1925
|
+
this.#synchronousResult = computed(() => {
|
|
1926
|
+
const dataSources = this.#dataSources();
|
|
1927
|
+
if (dataSources?.dataProvider?.() !== undefined) {
|
|
1928
|
+
return undefined;
|
|
1929
|
+
}
|
|
1930
|
+
if (dataSources?.dataListResult?.() !== undefined) {
|
|
1931
|
+
return dataSources?.dataListResult();
|
|
1932
|
+
}
|
|
1933
|
+
if (dataSources?.arrayItems?.() !== undefined) {
|
|
1934
|
+
return { data: dataSources.arrayItems(), totalCount: dataSources.arrayItems()?.length ?? 0 };
|
|
1935
|
+
}
|
|
1936
|
+
return undefined;
|
|
1937
|
+
}, ...(ngDevMode ? [{ debugName: "#synchronousResult" }] : []));
|
|
1938
|
+
this.#dataProvider = computed(() => this.#dataSources()?.dataProvider?.(), ...(ngDevMode ? [{ debugName: "#dataProvider" }] : []));
|
|
1939
|
+
this.#dataProviderService = computed(() => {
|
|
1940
|
+
const dataProvider = this.#dataProvider();
|
|
1941
|
+
return dataProvider?.serviceType ? this.#injector.get(dataProvider.serviceType) : null;
|
|
1942
|
+
}, ...(ngDevMode ? [{ debugName: "#dataProviderService" }] : []));
|
|
1943
|
+
this.#synchronousResultEffect = effectWithDeps([this.#synchronousResult], ([res]) => {
|
|
1944
|
+
if (res != null) {
|
|
1945
|
+
this.#setData(res.data ?? [], res.totalCount);
|
|
1946
|
+
}
|
|
1947
|
+
});
|
|
1948
|
+
this.#synchronousLoadingEffect = effectWithDeps([this.#synchronousResult, this.#manualLoading], ([res, manualLoading]) => {
|
|
1949
|
+
if (res != null && manualLoading == null) {
|
|
1950
|
+
this.#loading.set(false);
|
|
1951
|
+
}
|
|
1952
|
+
});
|
|
1953
|
+
this.#manualLoadingEffect = effectWithDeps([this.#manualLoading], ([manualLoading]) => {
|
|
1954
|
+
if (manualLoading != null) {
|
|
1955
|
+
this.#loading.set(manualLoading);
|
|
1956
|
+
}
|
|
1957
|
+
});
|
|
1958
|
+
// pagination
|
|
1959
|
+
this.#params = signal(undefined, ...(ngDevMode ? [{ debugName: "#params" }] : []));
|
|
1960
|
+
this.params = this.#params.asReadonly();
|
|
1961
|
+
this.#sortStates = signal(undefined, ...(ngDevMode ? [{ debugName: "#sortStates" }] : []));
|
|
1962
|
+
this.sortStates = this.#sortStates.asReadonly();
|
|
1963
|
+
this.#filterStates = signal({}, ...(ngDevMode ? [{ debugName: "#filterStates" }] : []));
|
|
1964
|
+
this.filterStates = this.#filterStates.asReadonly();
|
|
1965
|
+
this.primeFilterStates = computed(() => {
|
|
1966
|
+
const filterStates = this.#filterStates();
|
|
1967
|
+
const searchState = this.#searchState();
|
|
1968
|
+
const primeFilterStates = { ...filterStates };
|
|
1969
|
+
if (searchState != null) {
|
|
1970
|
+
primeFilterStates['global'] = { ...searchState, matchMode: 'contains' };
|
|
1971
|
+
}
|
|
1972
|
+
return primeFilterStates;
|
|
1973
|
+
}, ...(ngDevMode ? [{ debugName: "primeFilterStates" }] : []));
|
|
1974
|
+
this.#isSortAndFilterMetaInitialized = signal(false, ...(ngDevMode ? [{ debugName: "#isSortAndFilterMetaInitialized" }] : []));
|
|
1975
|
+
this.#defaultParamsEffect = effectWithDeps([this.#metadata.defaultParams], ([defaultParams]) => {
|
|
1976
|
+
this.#sortStates.set(tableCreateSortMeta(defaultParams));
|
|
1977
|
+
this.#filterStates.set(tableCreateFilterMeta(defaultParams));
|
|
1978
|
+
this.#isSortAndFilterMetaInitialized.set(true);
|
|
1979
|
+
}, { firstOnly: true });
|
|
1980
|
+
this.#isSearchMetaInitialized = signal(false, ...(ngDevMode ? [{ debugName: "#isSearchMetaInitialized" }] : []));
|
|
1981
|
+
this.#searchState = signal(undefined, ...(ngDevMode ? [{ debugName: "#searchState" }] : []));
|
|
1982
|
+
this.searchState = this.#searchState.asReadonly();
|
|
1983
|
+
this.isAllPaginationMetaInitialized = computed(() => this.#isSortAndFilterMetaInitialized() && this.#isSortAndFilterMetaInitialized(), ...(ngDevMode ? [{ debugName: "isAllPaginationMetaInitialized" }] : []));
|
|
1984
|
+
this.paginationMode = computed(() => {
|
|
1985
|
+
const descriptor = this.#metadata.descriptor();
|
|
1986
|
+
if (descriptor.paginationMode != null) {
|
|
1987
|
+
// descriptor choice is the strongest - if defined, use this value
|
|
1988
|
+
return descriptor.paginationMode;
|
|
1989
|
+
}
|
|
1990
|
+
else if (this.#dataProvider() != null) {
|
|
1991
|
+
// when data provider is used, use pagination
|
|
1992
|
+
return TablePaginationModeEnum.Pagination;
|
|
1993
|
+
}
|
|
1994
|
+
else {
|
|
1995
|
+
return TablePaginationModeEnum.None;
|
|
1996
|
+
}
|
|
1997
|
+
}, ...(ngDevMode ? [{ debugName: "paginationMode" }] : []));
|
|
1998
|
+
this.offset = computed(() => this.params()?.offset ?? 0, ...(ngDevMode ? [{ debugName: "offset" }] : []));
|
|
1999
|
+
this.rows = computed(() => {
|
|
2000
|
+
const params = this.params();
|
|
2001
|
+
if (params?.limit) {
|
|
2002
|
+
return params.limit;
|
|
2003
|
+
}
|
|
2004
|
+
const descriptor = this.#metadata.descriptor();
|
|
2005
|
+
const rowsPerPageOptions = this.#metadata.rowsPerPageOptions();
|
|
2006
|
+
if (descriptor.defaultNumRows && rowsPerPageOptions.includes(descriptor.defaultNumRows)) {
|
|
2007
|
+
return descriptor.defaultNumRows;
|
|
2008
|
+
}
|
|
2009
|
+
return rowsPerPageOptions[0];
|
|
2010
|
+
}, ...(ngDevMode ? [{ debugName: "rows" }] : []));
|
|
2011
|
+
// data
|
|
2012
|
+
this.#data = signal([], ...(ngDevMode ? [{ debugName: "#data" }] : []));
|
|
2013
|
+
this.data = this.#data.asReadonly();
|
|
2014
|
+
this.#count = signal(0, ...(ngDevMode ? [{ debugName: "#count" }] : []));
|
|
2015
|
+
this.count = this.#count.asReadonly();
|
|
2016
|
+
this.#loading = signal(false, ...(ngDevMode ? [{ debugName: "#loading" }] : []));
|
|
2017
|
+
this.loading = this.#loading.asReadonly();
|
|
2018
|
+
this.selectedItems = signal([], ...(ngDevMode ? [{ debugName: "selectedItems" }] : []));
|
|
2019
|
+
this.#destroyRef.onDestroy(() => this.#dataProviderSubscription?.unsubscribe());
|
|
2020
|
+
}
|
|
2021
|
+
setDataSources(arrayItems, dataListResult, dataProvider, manualLoading) {
|
|
2022
|
+
this.#dataSources.set({ arrayItems, dataListResult, dataProvider, manualLoading });
|
|
2023
|
+
}
|
|
2024
|
+
setPrimeTable(cmp) {
|
|
2025
|
+
this.#primeTable = cmp;
|
|
2026
|
+
}
|
|
2027
|
+
fetchWithDataProvider(paramsList, onErrorFn) {
|
|
2028
|
+
// remove disabled filters from fetch
|
|
2029
|
+
const params = {
|
|
2030
|
+
...paramsList,
|
|
2031
|
+
filters: paramsList.filters ? Object.fromEntries(Object.entries(paramsList.filters).filter(([_, f]) => !f?.disabled)) : undefined
|
|
2032
|
+
};
|
|
2033
|
+
const dataProvider = this.#dataProvider();
|
|
2034
|
+
if (!dataProvider || params.limit === 0) {
|
|
2035
|
+
return false;
|
|
2036
|
+
}
|
|
2037
|
+
this.#dataProviderSubscription?.unsubscribe();
|
|
2038
|
+
this.#loading.set(true);
|
|
2039
|
+
this.#dataProviderSubscription = toObservable$1(dataProvider.getAll(params, this.#dataProviderService(), this.#metadata.descriptor().isLocalized ? (this.#commons.appDataLocale() ?? undefined) : undefined)).subscribe({
|
|
2040
|
+
next: res => {
|
|
2041
|
+
const descriptorInput = this.#metadata.descriptorFromSource();
|
|
2042
|
+
if (descriptorInput instanceof TableDynamicDescriptorInst) {
|
|
2043
|
+
this.#metadata.setDescriptor(descriptorInput.toTableDescriptorFromData(res));
|
|
2044
|
+
}
|
|
2045
|
+
this.#setData(res?.data ?? [], res?.totalCount);
|
|
2046
|
+
this.#loading.set(false);
|
|
2047
|
+
},
|
|
2048
|
+
error: err => {
|
|
2049
|
+
onErrorFn(err);
|
|
2050
|
+
this.#setData([]);
|
|
2051
|
+
this.#loading.set(false);
|
|
2052
|
+
}
|
|
2053
|
+
});
|
|
2054
|
+
return true;
|
|
2055
|
+
}
|
|
2056
|
+
setParams(params, fromQueryParams = false) {
|
|
2057
|
+
if (!fromQueryParams && this.compareWithCurrentParams(params)) {
|
|
2058
|
+
return;
|
|
2059
|
+
}
|
|
2060
|
+
this.#params.set(params);
|
|
2061
|
+
this.#sortStates.set(tableCreateSortMeta(params));
|
|
2062
|
+
this.#filterStates.set(tableCreateFilterMeta(params));
|
|
2063
|
+
this.#isSortAndFilterMetaInitialized.set(true);
|
|
2064
|
+
if (fromQueryParams && !this.#isSearchMetaInitialized() && params?.search) {
|
|
2065
|
+
this.#searchState.set({ value: params.search, caseSensitive: params.filters?.['global']?.caseSensitive ?? false });
|
|
2066
|
+
}
|
|
2067
|
+
this.#isSearchMetaInitialized.set(true);
|
|
2068
|
+
}
|
|
2069
|
+
/**
|
|
2070
|
+
* Updates primeNG component with new filters and triggers data reload (if lazy load) or inline filtering.ž
|
|
2071
|
+
* Usually setting the params should trigger the cycle to load data and calculate other states (sort, filter, search, etc.) from params.
|
|
2072
|
+
* In case of PrimeNG's inline filtering, the internal primeNG state must be updated first and the states must subsequently be updated via callback functions.
|
|
2073
|
+
*
|
|
2074
|
+
* @param filters - { [fieldName]: FilterState | undefined } where:
|
|
2075
|
+
* - fieldName = column field identifier
|
|
2076
|
+
* - FilterState = full filter config
|
|
2077
|
+
* - undefined = clears filter for that field
|
|
2078
|
+
*/
|
|
2079
|
+
updateFilters(filters) {
|
|
2080
|
+
if (!this.#primeTable)
|
|
2081
|
+
return;
|
|
2082
|
+
for (const key of Object.keys(filters)) {
|
|
2083
|
+
this.#primeTable.filters[key] = { ...filters[key] };
|
|
2084
|
+
}
|
|
2085
|
+
this.#primeTable._filter();
|
|
2086
|
+
}
|
|
2087
|
+
updateSearch(search) {
|
|
2088
|
+
if (!this.#primeTable)
|
|
2089
|
+
return;
|
|
2090
|
+
this.#primeTable.filters['global'] = { ...search, matchMode: 'contains' };
|
|
2091
|
+
this.#primeTable._filter();
|
|
2092
|
+
}
|
|
2093
|
+
/**
|
|
2094
|
+
* Compare the given params with the stored params in the DataListService.
|
|
2095
|
+
*
|
|
2096
|
+
* @param {DataListParams} params - The params to compare with the stored params.
|
|
2097
|
+
*
|
|
2098
|
+
* @return {boolean} - True if the given params match the stored params, otherwise false.
|
|
2099
|
+
*/
|
|
2100
|
+
compareWithCurrentParams(params) {
|
|
2101
|
+
return (params.offset === this.offset() &&
|
|
2102
|
+
params.limit === this.rows() &&
|
|
2103
|
+
JSON.stringify(tableCreateSortMeta(params)) === JSON.stringify(this.#sortStates()) &&
|
|
2104
|
+
JSON.stringify(tableCreateFilterMeta(params)) === JSON.stringify(this.#filterStates()));
|
|
2105
|
+
}
|
|
2106
|
+
#setData(data, count) {
|
|
2107
|
+
this.#data.set([...data]);
|
|
2108
|
+
this.#count.set(count ?? data.length);
|
|
2109
|
+
}
|
|
2110
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableDataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2111
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableDataService }); }
|
|
2112
|
+
}
|
|
2113
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableDataService, decorators: [{
|
|
2114
|
+
type: Injectable
|
|
2115
|
+
}], ctorParameters: () => [] });
|
|
2116
|
+
|
|
2117
|
+
/**
|
|
2118
|
+
* generates table layout preferences key used when saving preferences to localstorage
|
|
2119
|
+
* @param typeName string, required
|
|
2120
|
+
* @param url string, required
|
|
2121
|
+
* @param trackProperty string, not required
|
|
2122
|
+
*/
|
|
2123
|
+
function generateTableLayoutPrefsKey(typeName, url, trackProperty) {
|
|
2124
|
+
return `commonsTableLayoutPrefs~~${typeName}~~${trackProperty ?? url.split('?')[0].split('#')[0]}`;
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
class TablePreferencesService {
|
|
2128
|
+
constructor() {
|
|
2129
|
+
this.#router = inject(Router);
|
|
2130
|
+
this.#storageService = inject(CommonsStorageService);
|
|
2131
|
+
this.#metadata = inject(TableMetadataService);
|
|
2132
|
+
this.localstorageKey = computed(() => {
|
|
2133
|
+
const descriptor = this.#metadata.descriptor();
|
|
2134
|
+
return descriptor.model.i18nBaseKey ? generateTableLayoutPrefsKey(descriptor.model.i18nBaseKey, this.#router.url, descriptor.identifier) : null;
|
|
2135
|
+
}, ...(ngDevMode ? [{ debugName: "localstorageKey" }] : []));
|
|
2136
|
+
this.#layoutPrefsSaveCnt = signal(0, ...(ngDevMode ? [{ debugName: "#layoutPrefsSaveCnt" }] : []));
|
|
2137
|
+
this.layoutPreferences = computed(() => {
|
|
2138
|
+
const lsKey = this.localstorageKey();
|
|
2139
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2140
|
+
const cnt = this.#layoutPrefsSaveCnt(); // needed to force updates on user changes
|
|
2141
|
+
const layoutPrefs = lsKey ? this.#storageService.getItem(TableMetadataService.cmpTypeName, lsKey) : undefined;
|
|
2142
|
+
return layoutPrefs ?? { columnWidths: {} };
|
|
2143
|
+
}, ...(ngDevMode ? [{ debugName: "layoutPreferences" }] : []));
|
|
2144
|
+
// columns
|
|
2145
|
+
this.columnsWithPrefs = computed(() => this.#computeColumnsWithLayout(), ...(ngDevMode ? [{ debugName: "columnsWithPrefs" }] : []));
|
|
2146
|
+
}
|
|
2147
|
+
#router;
|
|
2148
|
+
#storageService;
|
|
2149
|
+
#metadata;
|
|
2150
|
+
#layoutPrefsSaveCnt;
|
|
2151
|
+
/**
|
|
2152
|
+
* Method is called on column resize
|
|
2153
|
+
* @param element event's element
|
|
2154
|
+
*/
|
|
2155
|
+
onColumnResize({ element }) {
|
|
2156
|
+
const fieldId = element.id;
|
|
2157
|
+
const width = element.offsetWidth;
|
|
2158
|
+
const layoutPrefs = this.layoutPreferences();
|
|
2159
|
+
const col = this.columnsWithPrefs().find(el => el.descriptor.property === fieldId);
|
|
2160
|
+
if (col)
|
|
2161
|
+
col.width = width;
|
|
2162
|
+
if (!layoutPrefs.columnWidths)
|
|
2163
|
+
layoutPrefs.columnWidths = {};
|
|
2164
|
+
layoutPrefs.columnWidths[fieldId] = width;
|
|
2165
|
+
this.#saveLayoutPreferences(layoutPrefs);
|
|
2166
|
+
}
|
|
2167
|
+
onColumnToggle(event) {
|
|
2168
|
+
const layoutPrefs = this.layoutPreferences();
|
|
2169
|
+
const selectedColumns = event.value.map(v => v.descriptor.property);
|
|
2170
|
+
layoutPrefs.columnHidden = this.columnsWithPrefs()
|
|
2171
|
+
.filter(c => selectedColumns.indexOf(c.descriptor.property) < 0)
|
|
2172
|
+
.map(c => c.descriptor.property);
|
|
2173
|
+
this.#saveLayoutPreferences(layoutPrefs, true);
|
|
2174
|
+
}
|
|
2175
|
+
onColumnToggleAll() {
|
|
2176
|
+
const layoutPrefs = this.layoutPreferences();
|
|
2177
|
+
const columns = [...this.columnsWithPrefs()];
|
|
2178
|
+
const isVisible = !this.columnsWithPrefs().some(c => c.isVisible);
|
|
2179
|
+
for (const col of columns) {
|
|
2180
|
+
if (isVisible !== col.isVisible) {
|
|
2181
|
+
col.isVisible = isVisible;
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
layoutPrefs.columnHidden = columns.filter(c => !c.isVisible).map(c => c.descriptor.property);
|
|
2185
|
+
this.#saveLayoutPreferences(layoutPrefs, true);
|
|
2186
|
+
}
|
|
2187
|
+
onColumnReorder(event) {
|
|
2188
|
+
if (event.dropIndex !== undefined && event.dropIndex >= 0 && event.dragIndex !== undefined && event.dragIndex >= 0 && event.dropIndex !== event.dragIndex) {
|
|
2189
|
+
const eventDropIndex = event.dropIndex;
|
|
2190
|
+
const eventDragIndex = event.dragIndex;
|
|
2191
|
+
const prevVisibleColumns = this.columnsWithPrefs().filter(c => c.isVisible);
|
|
2192
|
+
const colAtDrop = prevVisibleColumns[eventDropIndex];
|
|
2193
|
+
const colAtDrag = prevVisibleColumns[eventDragIndex];
|
|
2194
|
+
const colAtDropIndex = this.columnsWithPrefs().findIndex(el => el.id === colAtDrop.id);
|
|
2195
|
+
const colAtDragIndex = this.columnsWithPrefs().findIndex(el => el.id === colAtDrag.id);
|
|
2196
|
+
if (colAtDropIndex > -1 && colAtDragIndex > -1) {
|
|
2197
|
+
let columns = [...this.columnsWithPrefs()];
|
|
2198
|
+
columns.splice(colAtDragIndex, 1);
|
|
2199
|
+
const dropIndex = columns.findIndex(el => el.id === colAtDrop.id) + (eventDropIndex > eventDragIndex ? 1 : 0);
|
|
2200
|
+
columns = [...columns.slice(0, dropIndex), colAtDrag, ...columns.slice(dropIndex)];
|
|
2201
|
+
const layoutPrefs = this.layoutPreferences();
|
|
2202
|
+
layoutPrefs.columnOrder = columns.map(el => el.descriptor.property);
|
|
2203
|
+
this.#saveLayoutPreferences(layoutPrefs);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
/**
|
|
2208
|
+
* Reset column order and column visibility to default settings
|
|
2209
|
+
*/
|
|
2210
|
+
clearLayoutPreferences() {
|
|
2211
|
+
const key = this.localstorageKey();
|
|
2212
|
+
if (key) {
|
|
2213
|
+
this.#storageService.removeItem(TableMetadataService.cmpTypeName, key);
|
|
2214
|
+
this.#layoutPrefsSaveCnt.update(v => v + 1);
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
#saveLayoutPreferences(layoutPrefs, forceUpdate = false) {
|
|
2218
|
+
const key = this.localstorageKey();
|
|
2219
|
+
if (key) {
|
|
2220
|
+
this.#storageService.setItem(TableMetadataService.cmpTypeName, key, layoutPrefs);
|
|
2221
|
+
if (forceUpdate) {
|
|
2222
|
+
this.#layoutPrefsSaveCnt.update(v => v + 1);
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
#computeColumnsWithLayout() {
|
|
2227
|
+
const descriptor = this.#metadata.descriptor();
|
|
2228
|
+
const layoutPrefs = this.layoutPreferences();
|
|
2229
|
+
// initialize columns with additional properties
|
|
2230
|
+
const timestamp = new Date().getTime();
|
|
2231
|
+
const columns = descriptor.columns.map(col => ({
|
|
2232
|
+
id: `${col.property}-${timestamp}`,
|
|
2233
|
+
descriptor: col,
|
|
2234
|
+
filter: this.#metadata
|
|
2235
|
+
.filters()
|
|
2236
|
+
.find(f => f.descriptor.showOnColumn === col.property &&
|
|
2237
|
+
((f.descriptor.displayType == null && this.#metadata.defaultFilterDisplayType === FilterDisplayTypeEnum.Column) ||
|
|
2238
|
+
f.descriptor.displayType === FilterDisplayTypeEnum.Column)),
|
|
2239
|
+
sort: descriptor.sorts.find(f => f.showOnColumn === col.property),
|
|
2240
|
+
disabled: !col.isToggleable,
|
|
2241
|
+
isVisible: layoutPrefs.columnHidden ? !layoutPrefs.columnHidden.includes(col.property) : col.isVisible,
|
|
2242
|
+
width: layoutPrefs.columnWidths?.[col.property]
|
|
2243
|
+
}));
|
|
2244
|
+
if (layoutPrefs.columnOrder) {
|
|
2245
|
+
for (let i = 0; i < layoutPrefs.columnOrder.length; i++) {
|
|
2246
|
+
const colName = layoutPrefs.columnOrder[i];
|
|
2247
|
+
const colWithPrefs = columns.find(el => el.descriptor.property === colName);
|
|
2248
|
+
if (colWithPrefs) {
|
|
2249
|
+
colWithPrefs.orderIdx = i;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
return columns.sort((a, b) => (a.orderIdx !== undefined && b.orderIdx !== undefined ? a.orderIdx - b.orderIdx : 0));
|
|
2254
|
+
}
|
|
2255
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TablePreferencesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2256
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TablePreferencesService }); }
|
|
2257
|
+
}
|
|
2258
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TablePreferencesService, decorators: [{
|
|
2259
|
+
type: Injectable
|
|
2260
|
+
}] });
|
|
2261
|
+
|
|
2262
|
+
class TableRemovableSortDirective {
|
|
2263
|
+
#pTable = inject(Table);
|
|
2264
|
+
constructor() {
|
|
2265
|
+
this.#overrideSortMethod(this.#pTable);
|
|
2266
|
+
}
|
|
2267
|
+
#overrideSortMethod(pTable) {
|
|
2268
|
+
pTable.sort = (event) => {
|
|
2269
|
+
const originalEvent = event.originalEvent;
|
|
2270
|
+
const metaKey = originalEvent.metaKey || originalEvent.ctrlKey;
|
|
2271
|
+
const sortMeta = pTable.getSortMeta(event.field);
|
|
2272
|
+
if (sortMeta) {
|
|
2273
|
+
if (!metaKey) {
|
|
2274
|
+
this.#updateSingleSortMeta(pTable, sortMeta, event.field);
|
|
2275
|
+
}
|
|
2276
|
+
else {
|
|
2277
|
+
this.#updateMultiSortMeta(pTable, sortMeta);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
else {
|
|
2281
|
+
this.#addNewSortMeta(pTable, metaKey, event.field);
|
|
2282
|
+
}
|
|
2283
|
+
this.#applySort(pTable);
|
|
2284
|
+
if (pTable.isStateful()) {
|
|
2285
|
+
pTable.saveState();
|
|
2286
|
+
}
|
|
2287
|
+
pTable.anchorRowIndex = null;
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
#updateSingleSortMeta(pTable, sortMeta, field) {
|
|
2291
|
+
if (pTable.multiSortMeta && pTable.multiSortMeta.length > 1) {
|
|
2292
|
+
pTable.multiSortMeta = [{ field, order: pTable.defaultSortOrder }];
|
|
2293
|
+
}
|
|
2294
|
+
else if (sortMeta.order === -1) {
|
|
2295
|
+
pTable.multiSortMeta = [];
|
|
2296
|
+
}
|
|
2297
|
+
else {
|
|
2298
|
+
pTable.multiSortMeta = [{ field, order: sortMeta.order * -1 }];
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
#updateMultiSortMeta(pTable, sortMeta) {
|
|
2302
|
+
pTable.multiSortMeta ??= [];
|
|
2303
|
+
for (let i = 0; i < pTable.multiSortMeta.length; i++) {
|
|
2304
|
+
if (pTable.multiSortMeta[i].field === sortMeta.field) {
|
|
2305
|
+
pTable.multiSortMeta.splice(i, 1);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
if (sortMeta.order === 1) {
|
|
2309
|
+
sortMeta.order = sortMeta.order * -1;
|
|
2310
|
+
pTable.multiSortMeta?.push(sortMeta);
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
#addNewSortMeta(pTable, metaKey, field) {
|
|
2314
|
+
if (!metaKey || !pTable.multiSortMeta) {
|
|
2315
|
+
pTable.multiSortMeta = [];
|
|
2316
|
+
}
|
|
2317
|
+
pTable.multiSortMeta?.push({ field, order: pTable.defaultSortOrder });
|
|
2318
|
+
}
|
|
2319
|
+
#applySort(pTable) {
|
|
2320
|
+
if (pTable.multiSortMeta?.length === 0 && !pTable.lazy) {
|
|
2321
|
+
pTable.multiSortMeta = this.#defaultMultiSortMeta();
|
|
2322
|
+
}
|
|
2323
|
+
pTable.sortMultiple();
|
|
2324
|
+
}
|
|
2325
|
+
#defaultMultiSortMeta() {
|
|
2326
|
+
const multiSortMeta = this.#pTable.columns
|
|
2327
|
+
?.filter(column => column.sort?._defaultIsEnabled)
|
|
2328
|
+
.sort((a, b) => a.sort._defaultOrder - b.sort._defaultOrder)
|
|
2329
|
+
.map(column => ({ field: column.sort._property, order: column.sort._defaultIsAscending ? 1 : -1 }));
|
|
2330
|
+
if (!multiSortMeta || multiSortMeta.length === 0) {
|
|
2331
|
+
return [{ field: this.#pTable.columns?.filter(column => column.sort)?.[0].sort._property, order: 1 }];
|
|
2332
|
+
}
|
|
2333
|
+
return multiSortMeta;
|
|
2334
|
+
}
|
|
2335
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableRemovableSortDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2336
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: TableRemovableSortDirective, isStandalone: true, selector: "[mngRemovableSort]", ngImport: i0 }); }
|
|
2337
|
+
}
|
|
2338
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableRemovableSortDirective, decorators: [{
|
|
2339
|
+
type: Directive,
|
|
2340
|
+
args: [{
|
|
2341
|
+
selector: '[mngRemovableSort]'
|
|
2342
|
+
}]
|
|
2343
|
+
}], ctorParameters: () => [] });
|
|
2344
|
+
|
|
2345
|
+
class TableTemplateDirective extends TemplateDirective {
|
|
2346
|
+
constructor() {
|
|
2347
|
+
super(...arguments);
|
|
2348
|
+
this.name = input.required(...(ngDevMode ? [{ debugName: "name" }] : []));
|
|
2349
|
+
}
|
|
2350
|
+
// narrow the type of the context using the generic type of the directive.
|
|
2351
|
+
static ngTemplateContextGuard(dir, ctx) {
|
|
2352
|
+
return true;
|
|
2353
|
+
}
|
|
2354
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableTemplateDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2355
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.15", type: TableTemplateDirective, isStandalone: true, selector: "[mngTableTemplate]", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0 }); }
|
|
2356
|
+
}
|
|
2357
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableTemplateDirective, decorators: [{
|
|
2358
|
+
type: Directive,
|
|
2359
|
+
args: [{
|
|
2360
|
+
selector: '[mngTableTemplate]'
|
|
2361
|
+
}]
|
|
2362
|
+
}], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }] } });
|
|
2363
|
+
|
|
2364
|
+
class TableComponent {
|
|
2365
|
+
#primeTableEffect;
|
|
2366
|
+
// templates
|
|
2367
|
+
#templatesMerged;
|
|
2368
|
+
// subscriptions and refs
|
|
2369
|
+
#previousDataProvider;
|
|
2370
|
+
#dataProviderEagerFirstLoad;
|
|
2371
|
+
#dataProviderReloadSubscription;
|
|
2372
|
+
#routeQueryParamsSubscription;
|
|
2373
|
+
#routerEventsSubscription;
|
|
2374
|
+
#afterNextRenderRef;
|
|
2375
|
+
constructor() {
|
|
2376
|
+
this.filterKeyPrepend = 'f_';
|
|
2377
|
+
this.FilterTypeEnum = FilterTypeEnum;
|
|
2378
|
+
this.logger = inject(LoggerService).create(TableMetadataService.cmpTypeName);
|
|
2379
|
+
this.router = inject(Router);
|
|
2380
|
+
this.route = inject(ActivatedRoute);
|
|
2381
|
+
this.translate = inject(TranslateService);
|
|
2382
|
+
this.messageService = inject(MessageService);
|
|
2383
|
+
this.metadata = inject(TableMetadataService);
|
|
2384
|
+
this.prefs = inject(TablePreferencesService);
|
|
2385
|
+
this.data = inject((TableDataService));
|
|
2386
|
+
// descriptor
|
|
2387
|
+
this.descriptorInput = input.required(...(ngDevMode ? [{ debugName: "descriptorInput", alias: 'descriptor' }] : [{ alias: 'descriptor' }]));
|
|
2388
|
+
// data source inputs
|
|
2389
|
+
this.items = input(...(ngDevMode ? [undefined, { debugName: "items" }] : []));
|
|
2390
|
+
this.result = input(...(ngDevMode ? [undefined, { debugName: "result" }] : []));
|
|
2391
|
+
this.loadingInput = input(undefined, ...(ngDevMode ? [{ debugName: "loadingInput", alias: 'loading', transform: booleanOrUndefinedAttribute }] : [{ alias: 'loading', transform: booleanOrUndefinedAttribute }]));
|
|
2392
|
+
this.dataProvider = input(...(ngDevMode ? [undefined, { debugName: "dataProvider" }] : []));
|
|
2393
|
+
// extra features input
|
|
2394
|
+
this.useQueryParams = input(false, ...(ngDevMode ? [{ debugName: "useQueryParams", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
2395
|
+
this.cellClickEnabled = input(true, ...(ngDevMode ? [{ debugName: "cellClickEnabled", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
2396
|
+
this.selectionMode = input('multiple', ...(ngDevMode ? [{ debugName: "selectionMode" }] : []));
|
|
2397
|
+
this.selectionEnabled = input(false, ...(ngDevMode ? [{ debugName: "selectionEnabled", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
2398
|
+
this.rowReorderEnabledInput = input(true, ...(ngDevMode ? [{ debugName: "rowReorderEnabledInput", alias: 'rowReorderEnabled', transform: booleanAttribute }] : [{ alias: 'rowReorderEnabled', transform: booleanAttribute }]));
|
|
2399
|
+
this.rowReorderEnabled = computed(() => this.rowReorderEnabledInput() && this.metadata.descriptor().rowReorderable, ...(ngDevMode ? [{ debugName: "rowReorderEnabled" }] : []));
|
|
2400
|
+
this.expandedRowKeys = computed(() => {
|
|
2401
|
+
const descriptor = this.metadata.descriptor();
|
|
2402
|
+
if (typeof descriptor.isRowExpanded === 'string') {
|
|
2403
|
+
return this.data.data()?.reduce((acc, item) => {
|
|
2404
|
+
acc[item[descriptor.trackProperty]] = !!item[descriptor.isRowExpanded];
|
|
2405
|
+
return acc;
|
|
2406
|
+
}, {});
|
|
2407
|
+
}
|
|
2408
|
+
else if (typeof descriptor.isRowExpanded === 'function') {
|
|
2409
|
+
return this.data.data()?.reduce((acc, item) => {
|
|
2410
|
+
acc[item[descriptor.trackProperty]] = descriptor.isRowExpanded(item);
|
|
2411
|
+
return acc;
|
|
2412
|
+
}, {});
|
|
2413
|
+
}
|
|
2414
|
+
return {};
|
|
2415
|
+
}, ...(ngDevMode ? [{ debugName: "expandedRowKeys" }] : []));
|
|
2416
|
+
// styling
|
|
2417
|
+
this.columnLastMinWidth = input(...(ngDevMode ? [undefined, { debugName: "columnLastMinWidth" }] : []));
|
|
2418
|
+
this.columnsColspan = computed(() => this.visibleColumns().length + (this.hasLastColumn() ? 1 : 0) + (this.selectionEnabled() ? 1 : 0) + (this.rowReorderEnabled() ? 1 : 0), ...(ngDevMode ? [{ debugName: "columnsColspan" }] : []));
|
|
2419
|
+
this.hasTitleDisplay = computed(() => this.headerTitleTemplate() || this.metadata.descriptor().title, ...(ngDevMode ? [{ debugName: "hasTitleDisplay" }] : []));
|
|
2420
|
+
this.isCaptionVisible = computed(() => this.headerTemplate() || this.hasTitleDisplay() || this.tableHeaderFilters().length > 0 || this.metadata.descriptor().search, ...(ngDevMode ? [{ debugName: "isCaptionVisible" }] : []));
|
|
2421
|
+
// component inputs
|
|
2422
|
+
this.globalFilterFieldsInput = input(undefined, ...(ngDevMode ? [{ debugName: "globalFilterFieldsInput", alias: 'globalFilterFields' }] : [{ alias: 'globalFilterFields' }]));
|
|
2423
|
+
// cell click
|
|
2424
|
+
this.cellClickSubject = new Subject();
|
|
2425
|
+
this.isCellClickObserved = signal(this.cellClickSubject.observed, ...(ngDevMode ? [{ debugName: "isCellClickObserved" }] : []));
|
|
2426
|
+
this.isCellClickEnabled = computed(() => this.cellClickEnabled() && this.isCellClickObserved(), ...(ngDevMode ? [{ debugName: "isCellClickEnabled" }] : []));
|
|
2427
|
+
// event outputs
|
|
2428
|
+
this.tableLoad = output();
|
|
2429
|
+
this.cellClick = outputFromObservable(this.cellClickSubject);
|
|
2430
|
+
this.selectionChange = output();
|
|
2431
|
+
this.rowReorder = output();
|
|
2432
|
+
// content and view queries
|
|
2433
|
+
this.templates = input([], ...(ngDevMode ? [{ debugName: "templates" }] : []));
|
|
2434
|
+
this.contentTemplates = contentChildren(TableTemplateDirective, ...(ngDevMode ? [{ debugName: "contentTemplates" }] : []));
|
|
2435
|
+
this.primeTable = viewChild((Table), ...(ngDevMode ? [{ debugName: "primeTable" }] : []));
|
|
2436
|
+
this.#primeTableEffect = effectWithDeps([this.primeTable], ([table]) => this.data.setPrimeTable(table));
|
|
2437
|
+
// templates
|
|
2438
|
+
this.#templatesMerged = computed(() => [...this.contentTemplates(), ...this.templates()], ...(ngDevMode ? [{ debugName: "#templatesMerged" }] : []));
|
|
2439
|
+
this.headerTemplate = computed(() => findTemplateByName([...this.#templatesMerged()], 'header'), ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
|
|
2440
|
+
this.headerTitleTemplate = computed(() => findTemplateByName([...this.#templatesMerged()], 'headerTitle'), ...(ngDevMode ? [{ debugName: "headerTitleTemplate" }] : []));
|
|
2441
|
+
this.titleRowRightTemplate = computed(() => findTemplateByName([...this.#templatesMerged()], 'headerTitleRowRight'), ...(ngDevMode ? [{ debugName: "titleRowRightTemplate" }] : []));
|
|
2442
|
+
this.columnCustomLastTemplate = computed(() => findTemplateByName([...this.#templatesMerged()], 'columnCustomLast'), ...(ngDevMode ? [{ debugName: "columnCustomLastTemplate" }] : []));
|
|
2443
|
+
this.footerTemplate = computed(() => findTemplateByName([...this.#templatesMerged()], 'footer'), ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
|
|
2444
|
+
this.rowExpandTemplate = computed(() => findTemplateByName([...this.#templatesMerged()], 'rowExpandContent'), ...(ngDevMode ? [{ debugName: "rowExpandTemplate" }] : []));
|
|
2445
|
+
this.columnHeaderTemplate = computed(() => findTemplateByName([...this.#templatesMerged()], 'columnHeader'), ...(ngDevMode ? [{ debugName: "columnHeaderTemplate" }] : []));
|
|
2446
|
+
// data provider and items
|
|
2447
|
+
this.isLazy = computed(() => this.dataProvider()?.isLazy === true, ...(ngDevMode ? [{ debugName: "isLazy" }] : []));
|
|
2448
|
+
this.isPagination = computed(() => this.data.paginationMode() === TablePaginationModeEnum.Pagination, ...(ngDevMode ? [{ debugName: "isPagination" }] : []));
|
|
2449
|
+
// visual
|
|
2450
|
+
this.className = computed(() => {
|
|
2451
|
+
let className = this.metadata.descriptor().className ?? '';
|
|
2452
|
+
switch (this.metadata.descriptor().size) {
|
|
2453
|
+
case TableSizeEnum.Small:
|
|
2454
|
+
className += ' p-datatable-sm';
|
|
2455
|
+
break;
|
|
2456
|
+
case undefined:
|
|
2457
|
+
case TableSizeEnum.Large:
|
|
2458
|
+
className += ' p-datatable-lg';
|
|
2459
|
+
break;
|
|
2460
|
+
}
|
|
2461
|
+
if (this.metadata.descriptor().hasGridlines) {
|
|
2462
|
+
className += ' p-datatable-gridlines';
|
|
2463
|
+
}
|
|
2464
|
+
return className;
|
|
2465
|
+
}, ...(ngDevMode ? [{ debugName: "className" }] : []));
|
|
2466
|
+
// columns
|
|
2467
|
+
this.visibleColumns = computed(() => this.prefs.columnsWithPrefs().filter(col => col.isVisible), ...(ngDevMode ? [{ debugName: "visibleColumns" }] : []));
|
|
2468
|
+
this.areColumnsReorderable = computed(() => this.prefs.columnsWithPrefs().some(col => col.descriptor.isReorderable), ...(ngDevMode ? [{ debugName: "areColumnsReorderable" }] : []));
|
|
2469
|
+
this.areColumnsToggleable = computed(() => this.prefs.columnsWithPrefs().some(col => col.descriptor.isToggleable), ...(ngDevMode ? [{ debugName: "areColumnsToggleable" }] : []));
|
|
2470
|
+
// filter, sort
|
|
2471
|
+
this.hasColumnFilters = computed(() => (this.metadata.defaultFilterDisplayType === FilterDisplayTypeEnum.OverlayWithTag &&
|
|
2472
|
+
this.metadata.filterDescriptors().some(d => d.displayType === FilterDisplayTypeEnum.Column)) ||
|
|
2473
|
+
(this.metadata.defaultFilterDisplayType === FilterDisplayTypeEnum.Column && this.metadata.filterDescriptors().some(d => d.displayType == null)), ...(ngDevMode ? [{ debugName: "hasColumnFilters" }] : []));
|
|
2474
|
+
this.tableHeaderFilters = computed(() => {
|
|
2475
|
+
// statically defined filters AND generic filters
|
|
2476
|
+
const filters = this.metadata
|
|
2477
|
+
.filters()
|
|
2478
|
+
.filter(d => (d.descriptor.displayType == null &&
|
|
2479
|
+
[FilterDisplayTypeEnum.OverlayWithTag, FilterDisplayTypeEnum.DirectInput].includes(this.metadata.defaultFilterDisplayType)) ||
|
|
2480
|
+
(d.descriptor.displayType != null && [FilterDisplayTypeEnum.OverlayWithTag, FilterDisplayTypeEnum.DirectInput].includes(d.descriptor.displayType)));
|
|
2481
|
+
return filters.concat(this.metadata.genericFilters());
|
|
2482
|
+
}, ...(ngDevMode ? [{ debugName: "tableHeaderFilters" }] : []));
|
|
2483
|
+
this.requiredFiltersMissing = computed(() => {
|
|
2484
|
+
const paramsWithDefaults = this.data.params() ?? this.metadata.defaultParams();
|
|
2485
|
+
const requiredFilters = this.metadata
|
|
2486
|
+
.filters()
|
|
2487
|
+
.filter(f => f.descriptor.isRequired)
|
|
2488
|
+
.map(f => f.descriptor.property);
|
|
2489
|
+
return requiredFilters.some(filterProperty => {
|
|
2490
|
+
const filter = paramsWithDefaults.filters?.[filterProperty];
|
|
2491
|
+
return (filter === undefined ||
|
|
2492
|
+
filter.matchMode === undefined ||
|
|
2493
|
+
(!['exists', 'doesNotExist'].includes(filter.matchMode) && isFilterValueBlank(filter.value)));
|
|
2494
|
+
});
|
|
2495
|
+
}, ...(ngDevMode ? [{ debugName: "requiredFiltersMissing" }] : []));
|
|
2496
|
+
this.hasLastColumn = computed(() => this.columnCustomLastTemplate() || this.areColumnsToggleable() || this.areColumnsReorderable(), ...(ngDevMode ? [{ debugName: "hasLastColumn" }] : []));
|
|
2497
|
+
// other
|
|
2498
|
+
this.navigationOutOfTableInProgress = false;
|
|
2499
|
+
this.navigationInTableInProgress = false;
|
|
2500
|
+
this.#dataProviderEagerFirstLoad = effectWithDeps([this.dataProvider], ([dataProvider]) => {
|
|
2501
|
+
if (dataProvider?.isLazy === false) {
|
|
2502
|
+
this.loadTableWithDataProvider(this.metadata.defaultParams());
|
|
2503
|
+
}
|
|
2504
|
+
else if (this.#previousDataProvider && dataProvider) {
|
|
2505
|
+
this.reload();
|
|
2506
|
+
}
|
|
2507
|
+
this.#previousDataProvider = dataProvider;
|
|
2508
|
+
});
|
|
2509
|
+
this.#dataProviderReloadSubscription = toObservable(this.dataProvider)
|
|
2510
|
+
.pipe(switchMap(dp => dp?.tableReload$ ?? of({})), takeUntilDestroyed())
|
|
2511
|
+
.subscribe({
|
|
2512
|
+
next: e => {
|
|
2513
|
+
this.reload(e);
|
|
2514
|
+
}
|
|
2515
|
+
});
|
|
2516
|
+
this.#routeQueryParamsSubscription = toObservable(this.useQueryParams)
|
|
2517
|
+
.pipe(switchMap(useQp => (useQp ? this.route.queryParams : NEVER)), takeUntilDestroyed())
|
|
2518
|
+
.subscribe(qp => {
|
|
2519
|
+
this.loadTableFromRouteUpdate(qp);
|
|
2520
|
+
});
|
|
2521
|
+
this.#routerEventsSubscription = toObservable(this.useQueryParams)
|
|
2522
|
+
.pipe(switchMap(useQp => (useQp ? this.router.events : NEVER)), filter(e => (e instanceof NavigationStart && e.url.split('?')[0].split('#')[0] !== this.router.url.split('?')[0].split('#')[0]) ||
|
|
2523
|
+
e instanceof NavigationEnd ||
|
|
2524
|
+
e instanceof NavigationCancel ||
|
|
2525
|
+
e instanceof NavigationError), takeUntilDestroyed())
|
|
2526
|
+
.subscribe(e => {
|
|
2527
|
+
this.navigationOutOfTableInProgress = e instanceof NavigationStart;
|
|
2528
|
+
});
|
|
2529
|
+
this.#afterNextRenderRef = afterNextRender(() => {
|
|
2530
|
+
this.isCellClickObserved.set(this.cellClickSubject.observed);
|
|
2531
|
+
});
|
|
2532
|
+
this.metadata.setSignalSources(this.descriptorInput, this.globalFilterFieldsInput);
|
|
2533
|
+
this.data.setDataSources(this.items, this.result, this.dataProvider, this.loadingInput);
|
|
2534
|
+
}
|
|
2535
|
+
reload(emitEvent) {
|
|
2536
|
+
const params = emitEvent?.params ? emitEvent?.params : emitEvent?.resetParams ? undefined : this.lastParamsWithDefaults;
|
|
2537
|
+
const reloadParams = mergeDataListParamsWithDefaults(params ?? {}, this.metadata.defaultParams());
|
|
2538
|
+
this.loadTableWithDataProvider(reloadParams, emitEvent?.emitEvent ?? false);
|
|
2539
|
+
}
|
|
2540
|
+
onTableLazyLoad(event) {
|
|
2541
|
+
this.lastLazyLoadEvent = event;
|
|
2542
|
+
const params = fromTableLoadToDataListParams(event);
|
|
2543
|
+
if (this.useQueryParams()) {
|
|
2544
|
+
if (!this.navigationOutOfTableInProgress && !this.navigationInTableInProgress) {
|
|
2545
|
+
// this check is necessary: from some reason, primeNG commits one last lazy load event whenever any angular router navigation occurs
|
|
2546
|
+
this.navigationInTableInProgress = true;
|
|
2547
|
+
const newParams = dataListParamsToUrlQuery(params, this.metadata.defaultParams(), { prependFilterName: this.filterKeyPrepend, skipPresetDefaultsLimit: true });
|
|
2548
|
+
const newParamsWithParamsToRemove = { ...newParams };
|
|
2549
|
+
const currentQp = this.route.snapshot.queryParams;
|
|
2550
|
+
if (currentQp) {
|
|
2551
|
+
Object.keys(currentQp)
|
|
2552
|
+
.filter(k => (k.startsWith(this.filterKeyPrepend) || ['offset', 'limit', 'sort', 'q'].indexOf(k) >= 0) && newParams[k] === undefined)
|
|
2553
|
+
.forEach(k => (newParamsWithParamsToRemove[k] = null));
|
|
2554
|
+
}
|
|
2555
|
+
this.router
|
|
2556
|
+
.navigate([], {
|
|
2557
|
+
relativeTo: this.route,
|
|
2558
|
+
replaceUrl: true,
|
|
2559
|
+
queryParams: newParamsWithParamsToRemove,
|
|
2560
|
+
queryParamsHandling: 'merge'
|
|
2561
|
+
})
|
|
2562
|
+
.then(() => {
|
|
2563
|
+
this.navigationInTableInProgress = false;
|
|
2564
|
+
});
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
else {
|
|
2568
|
+
const paramsWithDefaults = mergeDataListParamsWithDefaults(params, this.metadata.defaultParams());
|
|
2569
|
+
this.data.setParams(paramsWithDefaults);
|
|
2570
|
+
this.loadTableWithDataProvider(paramsWithDefaults);
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
onTableFilter(event) {
|
|
2574
|
+
if (this.useQueryParams()) {
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
const params = fromTableLoadToDataListParams({ filters: event.filters });
|
|
2578
|
+
const paramsWithDefaults = mergeDataListParamsWithDefaults(params, this.metadata.defaultParams());
|
|
2579
|
+
// if table doesn't use lazy loading, filter params need to be set here
|
|
2580
|
+
// because the onTableLazyLoad event is not emitted
|
|
2581
|
+
if (!this.isLazy()) {
|
|
2582
|
+
this.data.setParams(paramsWithDefaults);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
onCellClick(event, col, item, idx) {
|
|
2586
|
+
if (!this.isCellClickEnabled()) {
|
|
2587
|
+
return;
|
|
2588
|
+
}
|
|
2589
|
+
const tableEvent = {
|
|
2590
|
+
column: col,
|
|
2591
|
+
rowItem: item,
|
|
2592
|
+
rowIndex: idx,
|
|
2593
|
+
event: event
|
|
2594
|
+
};
|
|
2595
|
+
this.cellClickSubject.next(tableEvent);
|
|
2596
|
+
}
|
|
2597
|
+
onSelectionChange(event) {
|
|
2598
|
+
this.data.selectedItems.set(event);
|
|
2599
|
+
this.selectionChange.emit(event);
|
|
2600
|
+
}
|
|
2601
|
+
onRowReorder(event) {
|
|
2602
|
+
this.rowReorder.emit(event);
|
|
2603
|
+
}
|
|
2604
|
+
loadTableWithDataProvider(paramsWithDefaults, emitEvent = true) {
|
|
2605
|
+
if (this.requiredFiltersMissing() && this.isLazy()) {
|
|
2606
|
+
return;
|
|
2607
|
+
}
|
|
2608
|
+
const isFetched = this.data.fetchWithDataProvider(paramsWithDefaults, error => {
|
|
2609
|
+
tableNotificationError(this.translate, this.messageService, this.metadata.descriptor(), error);
|
|
2610
|
+
const commonsError = fromSubscribeError(error, 'TableComponentError', {
|
|
2611
|
+
params: paramsWithDefaults
|
|
2612
|
+
});
|
|
2613
|
+
this.logger.log(commonsError, getErrorLogLevel(commonsError));
|
|
2614
|
+
});
|
|
2615
|
+
if (isFetched) {
|
|
2616
|
+
this.lastParamsWithDefaults = paramsWithDefaults;
|
|
2617
|
+
if (emitEvent) {
|
|
2618
|
+
const tableEvent = {
|
|
2619
|
+
originalEvent: this.lastLazyLoadEvent,
|
|
2620
|
+
params: paramsWithDefaults
|
|
2621
|
+
};
|
|
2622
|
+
this.tableLoad.emit(tableEvent);
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
loadTableFromRouteUpdate(urlParams) {
|
|
2627
|
+
const paramsWithDefaults = mergeDataListParamsWithDefaults(fromUrlQueryToDataListParams(urlParams, {
|
|
2628
|
+
prependFilterName: this.filterKeyPrepend,
|
|
2629
|
+
searchAsGlobal: true
|
|
2630
|
+
}), this.metadata.defaultParams());
|
|
2631
|
+
this.data.setParams(paramsWithDefaults, true);
|
|
2632
|
+
this.loadTableWithDataProvider(paramsWithDefaults);
|
|
2633
|
+
}
|
|
2634
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2635
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TableComponent, isStandalone: true, selector: "mng-table", inputs: { descriptorInput: { classPropertyName: "descriptorInput", publicName: "descriptor", isSignal: true, isRequired: true, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, result: { classPropertyName: "result", publicName: "result", isSignal: true, isRequired: false, transformFunction: null }, loadingInput: { classPropertyName: "loadingInput", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, dataProvider: { classPropertyName: "dataProvider", publicName: "dataProvider", isSignal: true, isRequired: false, transformFunction: null }, useQueryParams: { classPropertyName: "useQueryParams", publicName: "useQueryParams", isSignal: true, isRequired: false, transformFunction: null }, cellClickEnabled: { classPropertyName: "cellClickEnabled", publicName: "cellClickEnabled", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selectionEnabled: { classPropertyName: "selectionEnabled", publicName: "selectionEnabled", isSignal: true, isRequired: false, transformFunction: null }, rowReorderEnabledInput: { classPropertyName: "rowReorderEnabledInput", publicName: "rowReorderEnabled", isSignal: true, isRequired: false, transformFunction: null }, columnLastMinWidth: { classPropertyName: "columnLastMinWidth", publicName: "columnLastMinWidth", isSignal: true, isRequired: false, transformFunction: null }, globalFilterFieldsInput: { classPropertyName: "globalFilterFieldsInput", publicName: "globalFilterFields", isSignal: true, isRequired: false, transformFunction: null }, templates: { classPropertyName: "templates", publicName: "templates", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { tableLoad: "tableLoad", cellClick: "cellClick", selectionChange: "selectionChange", rowReorder: "rowReorder" }, host: { properties: { "class.mng-table-no-header": "!isCaptionVisible()" } }, providers: [TableMetadataService, TableDataService, { provide: ADataListService, useExisting: TableDataService }, TablePreferencesService], queries: [{ propertyName: "contentTemplates", predicate: TableTemplateDirective, isSignal: true }], viewQueries: [{ propertyName: "primeTable", first: true, predicate: (Table), descendants: true, isSignal: true }], ngImport: i0, template: "<div>\n <!-- MUST NOT use observable for value when using virtual scroll - does not work for some reason -->\n @if (data.isAllPaginationMetaInitialized()) {\n <p-table\n [value]=\"requiredFiltersMissing() ? [] : data.data()\"\n [dataKey]=\"metadata.descriptor().trackProperty\"\n [lazy]=\"isLazy()\"\n [loading]=\"data.loading()\"\n [paginator]=\"isPagination()\"\n [rows]=\"data.rows()\"\n [first]=\"data.offset()\"\n [totalRecords]=\"data.count()\"\n [rowsPerPageOptions]=\"metadata.rowsPerPageOptions()\"\n [showCurrentPageReport]=\"true\"\n [currentPageReportTemplate]=\"'mngTable.paginationMsg' | translate\"\n [multiSortMeta]=\"data.sortStates()\"\n [filters]=\"data.primeFilterStates()\"\n [globalFilterFields]=\"metadata.searchFields()\"\n sortMode=\"multiple\"\n [selection]=\"[]\"\n (selectionChange)=\"onSelectionChange($event)\"\n [selectionMode]=\"selectionEnabled() ? selectionMode() : null\"\n [scrollable]=\"true\"\n scrollHeight=\"flex\"\n [rowHover]=\"metadata.descriptor().hasHover\"\n [styleClass]=\"className()\"\n [resizableColumns]=\"metadata.descriptor().hasResizableColumns\"\n [columnResizeMode]=\"metadata.descriptor().columnResizeMode ?? 'expand'\"\n [reorderableColumns]=\"areColumnsReorderable()\"\n paginatorDropdownAppendTo=\"body\"\n [columns]=\"visibleColumns()\"\n [expandedRowKeys]=\"expandedRowKeys()\"\n (onColResize)=\"prefs.onColumnResize($event)\"\n (onColReorder)=\"prefs.onColumnReorder($event)\"\n (onLazyLoad)=\"onTableLazyLoad($event)\"\n (onFilter)=\"onTableFilter($event)\"\n (onRowReorder)=\"onRowReorder($event)\"\n mngRemovableSort>\n <ng-template #caption>\n @if (isCaptionVisible()) {\n <div class=\"table-header\">\n @if (headerTemplate()) {\n <ng-container *ngTemplateOutlet=\"headerTemplate(); context: {data: data.data(), totalCount: data.count(), table: this}\"></ng-container>\n } @else {\n <mng-table-header-with-filters\n [metadata]=\"tableHeaderFilters()\"\n [genericFilterDescriptor]=\"metadata.genericFilterDescriptor()\"\n [model]=\"metadata.descriptor().model\"\n [enableSearch]=\"metadata.descriptor().search\"\n [search]=\"data.searchState()\"\n [searchLimitWordMax]=\"metadata.descriptor().searchLimitMaxWords\"\n [enableCaseSensitive]=\"isLazy()\">\n @if (hasTitleDisplay()) {\n <ng-template mngTableHeaderWithFiltersTemplate name=\"title\">\n @if (headerTitleTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"headerTitleTemplate(); context: {data: data.data(), totalCount: data.count(), table: this}\"></ng-container>\n } @else if (metadata.descriptor().title) {\n <h5 class=\"p-0 m-0\">{{ metadata.descriptor().title! | translate }}</h5>\n }\n </ng-template>\n }\n @if (titleRowRightTemplate()) {\n <ng-template mngTableHeaderWithFiltersTemplate name=\"titleRowRight\">\n <ng-container *ngTemplateOutlet=\"titleRowRightTemplate()\"></ng-container>\n </ng-template>\n }\n </mng-table-header-with-filters>\n }\n </div>\n }\n </ng-template>\n <ng-template #header>\n @if (!metadata.descriptor().hideHeader) {\n <tr class=\"mng-table-header\" [class]=\"metadata.descriptor().headerClassName\">\n @if (selectionEnabled()) {\n @if (selectionMode() === 'multiple') {\n <th style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\">\n <p-tableHeaderCheckbox />\n </th>\n } @else {\n <!-- We need the line below, because otherwise p-tableRadioButton shifts the rest of the columns in table -->\n <th style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\"></th>\n }\n }\n @if (metadata.descriptor().rowExpandable) {\n <th scope=\"col\" pFrozenColumn [frozen]=\"true\"></th>\n }\n @if (rowReorderEnabled()) {\n <th scope=\"col\"></th>\n }\n @for (col of visibleColumns(); track col.id) {\n <ng-template #sortableColumnTHTemplate>\n @if (columnHeaderTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n columnHeaderTemplate();\n context: {data: data.data(), totalCount: data.count(), property: col.descriptor.property, table: this}\n \"></ng-container>\n } @else {\n <div class=\"flex justify-between items-center\">\n {{\n (col.descriptor.title && !col.descriptor.titleUseModelBase\n ? col.descriptor.title\n : (col.descriptor.title ?? col.descriptor.property | mngI18nProperty: metadata.descriptor().model)\n ) | translate\n }}\n <p-sortIcon [field]=\"col.sort?.property\" class=\"flex\"></p-sortIcon>\n </div>\n }\n </ng-template>\n <ng-template #nonSortableColumnTHTemplate>\n @if (columnHeaderTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n columnHeaderTemplate();\n context: {data: data.data(), totalCount: data.count(), property: col.descriptor.property, table: this}\n \"></ng-container>\n } @else {\n {{\n (col.descriptor.title && !col.descriptor.titleUseModelBase\n ? col.descriptor.title\n : (col.descriptor.title ?? col.descriptor.property | mngI18nProperty: metadata.descriptor().model)\n ) | translate\n }}\n }\n </ng-template>\n @if (col.descriptor.isReorderable) {\n <th\n pResizableColumn\n pReorderableColumn\n [id]=\"col.descriptor.property\"\n [pSortableColumn]=\"col.sort?.property\"\n [pSortableColumnDisabled]=\"!col.sort\"\n [style.width]=\"col.width ? col.width + 'px' : col.descriptor.width + '%'\"\n [style.min-width.px]=\"col.width ? null : col.descriptor.minWidth\"\n [style.max-width.px]=\"col.width ?? col.descriptor.maxWidth\"\n [class]=\"col.descriptor.headerClassName | mngTableFilterClass: col.filter?.descriptor : hasColumnFilters() && !col.width\">\n <ng-container *ngTemplateOutlet=\"col.sort ? sortableColumnTHTemplate : nonSortableColumnTHTemplate\"></ng-container>\n </th>\n } @else {\n <th\n pResizableColumn\n [id]=\"col.descriptor.property\"\n [pSortableColumn]=\"col.sort?.property\"\n [pSortableColumnDisabled]=\"!col.sort\"\n [style.width]=\"col.width ? col.width + 'px' : col.descriptor.width + '%'\"\n [style.min-width.px]=\"col.width ? null : col.descriptor.minWidth\"\n [style.max-width.px]=\"col.width ?? col.descriptor.maxWidth\"\n [class]=\"col.descriptor.headerClassName | mngTableFilterClass: col.filter?.descriptor : hasColumnFilters() && !col.width\">\n <ng-container *ngTemplateOutlet=\"col.sort ? sortableColumnTHTemplate : nonSortableColumnTHTemplate\"></ng-container>\n </th>\n }\n }\n @if (hasLastColumn()) {\n <th\n [style.min-width.px]=\"columnLastMinWidth()\"\n pFrozenColumn\n [frozen]=\"metadata.descriptor().actionColumnFrozen ?? areColumnsToggleable()\"\n alignFrozen=\"right\"\n class=\"mng-table-column-custom-last text-right!\">\n @if (areColumnsToggleable()) {\n @defer (on idle) {\n <mng-table-column-toggle [columns]=\"visibleColumns()\" />\n }\n }\n </th>\n }\n </tr>\n }\n @if (hasColumnFilters()) {\n <tr class=\"mng-column-filter-row\">\n <!-- We need the line below, because otherwise p-tableRadioButton shifts the rest of the columns in table -->\n @if (selectionEnabled()) {\n <th style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\"></th>\n }\n @if (rowReorderEnabled()) {\n <th scope=\"col\"></th>\n }\n @if (metadata.descriptor().rowExpandable) {\n <th scope=\"col\"></th>\n }\n @for (col of visibleColumns(); track col.id) {\n <th\n [class]=\"'px-1! ' + col.filter?.descriptor?.columnClassName | mngTableFilterClass: col.filter?.descriptor : hasColumnFilters() && !col.width\"\n [style.width.px]=\"col.width\"\n [style.width.%]=\"col.width ? null : (col.filter?.descriptor?.columnWidth ?? col.descriptor.width ?? null)\"\n [style.min-width.px]=\"col.width ? null : (col.filter?.descriptor?.columnMinWidth ?? col.descriptor.minWidth)\"\n [style.max-width.px]=\"col.width ?? col.descriptor.maxWidth\">\n @if (col.filter && col.filter.descriptor.filterType !== FilterTypeEnum.Component) {\n @defer (on idle) {\n <mng-table-filter [config]=\"col.filter\" [model]=\"metadata.descriptor().model\"></mng-table-filter>\n }\n } @else if (col.filter && col.filter.descriptor.customComponentType) {\n <ng-container [mngComponent]=\"col.filter.descriptor.customComponentType\" [inputs]=\"{descriptor: col.filter.descriptor}\"></ng-container>\n }\n </th>\n }\n @if (hasLastColumn()) {\n <th pFrozenColumn alignFrozen=\"right\" class=\"mng-table-column-custom-last\" [style.min-width.px]=\"columnLastMinWidth()\"></th>\n }\n </tr>\n }\n </ng-template>\n <ng-template #body let-item let-idx=\"rowIndex\" let-expanded=\"expanded\">\n <tr\n [pReorderableRow]=\"idx\"\n [ngClass]=\"\n metadata.descriptor().rowClassName | mngClassMap: metadata.descriptor().rowClassNameMapFn : item | mngLocaleDefaultRowClass: metadata.descriptor() : item\n \">\n @if (selectionEnabled()) {\n @if (selectionMode() === 'multiple') {\n <td style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\">\n <p-tableCheckbox [value]=\"item\"></p-tableCheckbox>\n </td>\n } @else {\n <td style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\">\n <p-tableRadioButton [value]=\"item\"></p-tableRadioButton>\n </td>\n }\n }\n @if (metadata.descriptor().rowExpandable) {\n <td>\n @let expandProp = metadata.descriptor().rowExpandableProperty;\n @if (!expandProp || item[expandProp]) {\n <button\n pButton\n type=\"button\"\n [pRowToggler]=\"item\"\n rounded=\"true\"\n text=\"true\"\n class=\"mng-button-sm\"\n [icon]=\"expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'\"></button>\n }\n </td>\n }\n @if (rowReorderEnabled()) {\n <td>\n <span class=\"pi pi-bars\" pReorderableRowHandle></span>\n </td>\n }\n @for (col of visibleColumns(); track col.id) {\n <td\n (click)=\"onCellClick($event, col.descriptor, item, idx)\"\n [class]=\"\n col.descriptor.className\n | mngClassMap: col.descriptor.classNameMapFn : item\n | mngTableFilterClass: col.filter?.descriptor : hasColumnFilters() && !col.width\n \"\n [class.clickable]=\"isCellClickEnabled()\"\n [style.width]=\"col.width ? col.width + 'px' : col.descriptor.width + '%'\"\n [style.min-width.px]=\"col.width ? null : col.descriptor.minWidth\"\n [style.max-width.px]=\"col.width ?? col.descriptor.maxWidth\">\n <mng-table-column-value [descriptor]=\"col.descriptor\" [item]=\"item\"></mng-table-column-value>\n </td>\n }\n @if (hasLastColumn()) {\n <td\n class=\"mng-table-column-custom-last justify-end text-right!\"\n [style.min-width.px]=\"columnLastMinWidth()\"\n pFrozenColumn\n alignFrozen=\"right\"\n [frozen]=\"metadata.descriptor().actionColumnFrozen ?? true\">\n @if (columnCustomLastTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n columnCustomLastTemplate();\n context: {item: item, index: idx, data: data.data(), totalCount: data.count(), table: this}\n \"></ng-container>\n }\n </td>\n }\n </tr>\n </ng-template>\n <ng-template #expandedrow let-item let-idx=\"rowIndex\">\n @if (metadata.descriptor().rowExpandable) {\n <tr>\n <td></td>\n <td [colSpan]=\"metadata.descriptor().rowExpandableColSpan\">\n @if (metadata.descriptor().rowExpandableComponentType !== undefined) {\n <ng-container [mngComponent]=\"metadata.descriptor().rowExpandableComponentType\" [inputs]=\"{item}\"> </ng-container>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n rowExpandTemplate();\n context: {item: item, index: idx, data: data.data(), totalCount: data.count(), table: this}\n \"></ng-container>\n }\n </td>\n </tr>\n }\n </ng-template>\n <ng-template #loadingicon>\n <div class=\"flex flex-col items-center\">\n @if (metadata.descriptor().loadingIcon) {\n <i [class]=\"'text-white text-4xl pi-spin ' + metadata.descriptor().loadingIcon\"></i>\n }\n @if (metadata.descriptor().loadingText) {\n <div class=\"text text-white text-lg font-semibold\" [ngClass]=\"{'mt-3': metadata.descriptor().loadingIcon}\">\n {{ metadata.descriptor().loadingText ?? '' | translate }}\n </div>\n }\n </div>\n </ng-template>\n <ng-template #loadingbody>\n <tr>\n <td [attr.colspan]=\"columnsColspan()\">\n <div class=\"loading-text\"></div>\n <p-skeleton width=\"100%\"></p-skeleton>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td [attr.colspan]=\"columnsColspan()\">\n @if (requiredFiltersMissing()) {\n <i class=\"pi pi-exclamation-triangle mr-2\"></i> <strong>{{ 'mngTable.requiredFiltersMissing' | translate }}</strong>\n } @else {\n {{ 'mngTable.noItems' | translate }}\n }\n </td>\n </tr>\n </ng-template>\n @if (footerTemplate()) {\n <ng-template #summary>\n <ng-container *ngTemplateOutlet=\"footerTemplate(); context: {data: data.data(), totalCount: data.count(), table: this}\"></ng-container>\n </ng-template>\n }\n </p-table>\n }\n</div>\n", styles: ["mng-table .p-datatable .p-datatable-header{border-top:0}mng-table .p-datatable:not(.p-datatable-gridlines) .p-datatable-tbody>tr>td{cursor:auto}mng-table .p-datatable:not(.p-datatable-gridlines) .p-datatable-tbody>tr>td.clickable{cursor:pointer}:is(mng-table .p-datatable .p-datatable-thead>tr>th,mng-table .p-datatable .p-datatable-tbody>tr>td):hover mng-table-column-value .help-buttons{display:block}mng-table .p-datatable .p-datatable-thead>tr>th.mng-table-column-custom-last{padding:var(--mng-table-column-head-custom-last, .1rem 1rem)}mng-table .p-datatable .p-datatable-tbody>tr>td{position:relative}mng-table .p-datatable .p-datatable-tbody>tr>td.mng-table-column-custom-last{padding-top:.1rem;padding-bottom:.1rem}mng-table .p-datatable .p-datatable-tbody>tr>td.p-datatable-frozen-column{position:sticky;z-index:1;background:transparent}mng-table .p-datatable.p-datatable-lg .p-datatable-tbody>tr>td.mng-table-column-custom-last{padding:var(--mng-table-column-body-custom-last, .15rem 1rem)}mng-table .p-datatable.p-datatable-sm .p-datatable-tbody>tr>td.mng-table-column-custom-last{padding:var(--mng-table-sm-column-body-custom-last, .05rem 1rem)}mng-table .p-datatable.p-datatable-flex-scrollable .p-datatable-thead>tr>th{overflow:hidden;text-overflow:ellipsis}mng-table .p-datatable.p-datatable-flex-scrollable .p-datatable-tbody>tr>td{overflow:hidden}mng-table .p-datatable .mng-table-row-localization-default-locale{background:var(--p-surface-100)!important}mng-table .mng-table-header>th:not(:first-child):not(:last-child){border-radius:0!important}mng-table .mng-table-header>th:first-child{border-top-right-radius:0!important;border-bottom-right-radius:0!important}mng-table .mng-table-header>th:last-child{border-radius:0!important}mng-table .mng-table-header .mng-table-columns-multiselect{width:36px}mng-table .mng-table-header .mng-table-columns-multiselect .p-multiselect-label-container{width:0}mng-table.mng-table-no-header p-datatable .p-datatable-header{display:none}mng-table.mng-table-header-compact .p-datatable-header{padding:var(--mng-table-header-compact-padding, 0 0 .5rem 0)!important}\n"], dependencies: [{ kind: "directive", type: ComponentDirective, selector: "[mngComponent]", inputs: ["mngComponent", "injectionToken", "inputs", "attachToHost", "parentInjector"], outputs: ["instanceCreated"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: TableColumnValueComponent, selector: "mng-table-column-value", inputs: ["descriptor", "item"] }, { kind: "component", type: TableHeaderWithFiltersComponent, selector: "mng-table-header-with-filters", inputs: ["metadata", "genericFilterDescriptor", "model", "enableSearch", "search", "searchLimitWordMax", "enableCaseSensitive"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$1.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i1$1.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i1$1.FrozenColumn, selector: "[pFrozenColumn]", inputs: ["frozen", "alignFrozen"] }, { kind: "directive", type: i1$1.RowToggler, selector: "[pRowToggler]", inputs: ["pRowToggler", "pRowTogglerDisabled"] }, { kind: "directive", type: i1$1.ResizableColumn, selector: "[pResizableColumn]", inputs: ["pResizableColumnDisabled"] }, { kind: "directive", type: i1$1.ReorderableColumn, selector: "[pReorderableColumn]", inputs: ["pReorderableColumnDisabled"] }, { kind: "component", type: i1$1.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i1$1.TableRadioButton, selector: "p-tableRadioButton", inputs: ["value", "disabled", "index", "inputId", "name", "ariaLabel"] }, { kind: "component", type: i1$1.TableCheckbox, selector: "p-tableCheckbox", inputs: ["value", "disabled", "required", "index", "inputId", "name", "ariaLabel"] }, { kind: "component", type: i1$1.TableHeaderCheckbox, selector: "p-tableHeaderCheckbox", inputs: ["disabled", "inputId", "name", "ariaLabel"] }, { kind: "directive", type: i1$1.ReorderableRowHandle, selector: "[pReorderableRowHandle]" }, { kind: "directive", type: i1$1.ReorderableRow, selector: "[pReorderableRow]", inputs: ["pReorderableRow", "pReorderableRowDisabled"] }, { kind: "component", type: Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "directive", type: ButtonDirective, selector: "[pButton]", inputs: ["ptButtonDirective", "hostName", "text", "plain", "raised", "size", "outlined", "rounded", "iconPos", "loadingIcon", "fluid", "label", "icon", "loading", "buttonProps", "severity"] }, { kind: "directive", type: TableRemovableSortDirective, selector: "[mngRemovableSort]" }, { kind: "directive", type: TableHeaderWithFiltersTemplateDirective, selector: "[mngTableHeaderWithFiltersTemplate]", inputs: ["name"] }, { kind: "pipe", type: I18nPropertyPipe, name: "mngI18nProperty" }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "pipe", type: ClassMapPipe, name: "mngClassMap" }, { kind: "pipe", type: LocaleDefaultRowClassPipe, name: "mngLocaleDefaultRowClass" }, { kind: "pipe", type: TableFilterClassPipe, name: "mngTableFilterClass" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None, deferBlockDependencies: [() => [import('./mediusinc-mng-commons-table-column-toggle.component-BQ99oqWO.mjs').then(m => m.TableColumnToggleComponent)], () => [Promise.resolve().then(function () { return filter_component; }).then(m => m.TableFilterComponent)]] }); }
|
|
2636
|
+
}
|
|
2637
|
+
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "20.3.15", ngImport: i0, type: TableComponent, resolveDeferredDeps: () => [import('./mediusinc-mng-commons-table-column-toggle.component-BQ99oqWO.mjs').then(m => m.TableColumnToggleComponent), Promise.resolve().then(function () { return filter_component; }).then(m => m.TableFilterComponent)], resolveMetadata: (TableColumnToggleComponent, TableFilterComponent) => ({ decorators: [{
|
|
2638
|
+
type: Component,
|
|
2639
|
+
args: [{ selector: 'mng-table', imports: [
|
|
2640
|
+
ComponentDirective,
|
|
2641
|
+
I18nPropertyPipe,
|
|
2642
|
+
TranslatePipe,
|
|
2643
|
+
NgClass,
|
|
2644
|
+
NgTemplateOutlet,
|
|
2645
|
+
TableColumnValueComponent,
|
|
2646
|
+
ClassMapPipe,
|
|
2647
|
+
LocaleDefaultRowClassPipe,
|
|
2648
|
+
TableFilterComponent,
|
|
2649
|
+
TableFilterClassPipe,
|
|
2650
|
+
TableHeaderWithFiltersComponent,
|
|
2651
|
+
FormsModule,
|
|
2652
|
+
TableModule,
|
|
2653
|
+
Skeleton,
|
|
2654
|
+
TableColumnToggleComponent,
|
|
2655
|
+
ButtonDirective,
|
|
2656
|
+
TableRemovableSortDirective,
|
|
2657
|
+
TableHeaderWithFiltersTemplateDirective
|
|
2658
|
+
], providers: [TableMetadataService, TableDataService, { provide: ADataListService, useExisting: TableDataService }, TablePreferencesService], host: {
|
|
2659
|
+
'[class.mng-table-no-header]': '!isCaptionVisible()'
|
|
2660
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div>\n <!-- MUST NOT use observable for value when using virtual scroll - does not work for some reason -->\n @if (data.isAllPaginationMetaInitialized()) {\n <p-table\n [value]=\"requiredFiltersMissing() ? [] : data.data()\"\n [dataKey]=\"metadata.descriptor().trackProperty\"\n [lazy]=\"isLazy()\"\n [loading]=\"data.loading()\"\n [paginator]=\"isPagination()\"\n [rows]=\"data.rows()\"\n [first]=\"data.offset()\"\n [totalRecords]=\"data.count()\"\n [rowsPerPageOptions]=\"metadata.rowsPerPageOptions()\"\n [showCurrentPageReport]=\"true\"\n [currentPageReportTemplate]=\"'mngTable.paginationMsg' | translate\"\n [multiSortMeta]=\"data.sortStates()\"\n [filters]=\"data.primeFilterStates()\"\n [globalFilterFields]=\"metadata.searchFields()\"\n sortMode=\"multiple\"\n [selection]=\"[]\"\n (selectionChange)=\"onSelectionChange($event)\"\n [selectionMode]=\"selectionEnabled() ? selectionMode() : null\"\n [scrollable]=\"true\"\n scrollHeight=\"flex\"\n [rowHover]=\"metadata.descriptor().hasHover\"\n [styleClass]=\"className()\"\n [resizableColumns]=\"metadata.descriptor().hasResizableColumns\"\n [columnResizeMode]=\"metadata.descriptor().columnResizeMode ?? 'expand'\"\n [reorderableColumns]=\"areColumnsReorderable()\"\n paginatorDropdownAppendTo=\"body\"\n [columns]=\"visibleColumns()\"\n [expandedRowKeys]=\"expandedRowKeys()\"\n (onColResize)=\"prefs.onColumnResize($event)\"\n (onColReorder)=\"prefs.onColumnReorder($event)\"\n (onLazyLoad)=\"onTableLazyLoad($event)\"\n (onFilter)=\"onTableFilter($event)\"\n (onRowReorder)=\"onRowReorder($event)\"\n mngRemovableSort>\n <ng-template #caption>\n @if (isCaptionVisible()) {\n <div class=\"table-header\">\n @if (headerTemplate()) {\n <ng-container *ngTemplateOutlet=\"headerTemplate(); context: {data: data.data(), totalCount: data.count(), table: this}\"></ng-container>\n } @else {\n <mng-table-header-with-filters\n [metadata]=\"tableHeaderFilters()\"\n [genericFilterDescriptor]=\"metadata.genericFilterDescriptor()\"\n [model]=\"metadata.descriptor().model\"\n [enableSearch]=\"metadata.descriptor().search\"\n [search]=\"data.searchState()\"\n [searchLimitWordMax]=\"metadata.descriptor().searchLimitMaxWords\"\n [enableCaseSensitive]=\"isLazy()\">\n @if (hasTitleDisplay()) {\n <ng-template mngTableHeaderWithFiltersTemplate name=\"title\">\n @if (headerTitleTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"headerTitleTemplate(); context: {data: data.data(), totalCount: data.count(), table: this}\"></ng-container>\n } @else if (metadata.descriptor().title) {\n <h5 class=\"p-0 m-0\">{{ metadata.descriptor().title! | translate }}</h5>\n }\n </ng-template>\n }\n @if (titleRowRightTemplate()) {\n <ng-template mngTableHeaderWithFiltersTemplate name=\"titleRowRight\">\n <ng-container *ngTemplateOutlet=\"titleRowRightTemplate()\"></ng-container>\n </ng-template>\n }\n </mng-table-header-with-filters>\n }\n </div>\n }\n </ng-template>\n <ng-template #header>\n @if (!metadata.descriptor().hideHeader) {\n <tr class=\"mng-table-header\" [class]=\"metadata.descriptor().headerClassName\">\n @if (selectionEnabled()) {\n @if (selectionMode() === 'multiple') {\n <th style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\">\n <p-tableHeaderCheckbox />\n </th>\n } @else {\n <!-- We need the line below, because otherwise p-tableRadioButton shifts the rest of the columns in table -->\n <th style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\"></th>\n }\n }\n @if (metadata.descriptor().rowExpandable) {\n <th scope=\"col\" pFrozenColumn [frozen]=\"true\"></th>\n }\n @if (rowReorderEnabled()) {\n <th scope=\"col\"></th>\n }\n @for (col of visibleColumns(); track col.id) {\n <ng-template #sortableColumnTHTemplate>\n @if (columnHeaderTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n columnHeaderTemplate();\n context: {data: data.data(), totalCount: data.count(), property: col.descriptor.property, table: this}\n \"></ng-container>\n } @else {\n <div class=\"flex justify-between items-center\">\n {{\n (col.descriptor.title && !col.descriptor.titleUseModelBase\n ? col.descriptor.title\n : (col.descriptor.title ?? col.descriptor.property | mngI18nProperty: metadata.descriptor().model)\n ) | translate\n }}\n <p-sortIcon [field]=\"col.sort?.property\" class=\"flex\"></p-sortIcon>\n </div>\n }\n </ng-template>\n <ng-template #nonSortableColumnTHTemplate>\n @if (columnHeaderTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n columnHeaderTemplate();\n context: {data: data.data(), totalCount: data.count(), property: col.descriptor.property, table: this}\n \"></ng-container>\n } @else {\n {{\n (col.descriptor.title && !col.descriptor.titleUseModelBase\n ? col.descriptor.title\n : (col.descriptor.title ?? col.descriptor.property | mngI18nProperty: metadata.descriptor().model)\n ) | translate\n }}\n }\n </ng-template>\n @if (col.descriptor.isReorderable) {\n <th\n pResizableColumn\n pReorderableColumn\n [id]=\"col.descriptor.property\"\n [pSortableColumn]=\"col.sort?.property\"\n [pSortableColumnDisabled]=\"!col.sort\"\n [style.width]=\"col.width ? col.width + 'px' : col.descriptor.width + '%'\"\n [style.min-width.px]=\"col.width ? null : col.descriptor.minWidth\"\n [style.max-width.px]=\"col.width ?? col.descriptor.maxWidth\"\n [class]=\"col.descriptor.headerClassName | mngTableFilterClass: col.filter?.descriptor : hasColumnFilters() && !col.width\">\n <ng-container *ngTemplateOutlet=\"col.sort ? sortableColumnTHTemplate : nonSortableColumnTHTemplate\"></ng-container>\n </th>\n } @else {\n <th\n pResizableColumn\n [id]=\"col.descriptor.property\"\n [pSortableColumn]=\"col.sort?.property\"\n [pSortableColumnDisabled]=\"!col.sort\"\n [style.width]=\"col.width ? col.width + 'px' : col.descriptor.width + '%'\"\n [style.min-width.px]=\"col.width ? null : col.descriptor.minWidth\"\n [style.max-width.px]=\"col.width ?? col.descriptor.maxWidth\"\n [class]=\"col.descriptor.headerClassName | mngTableFilterClass: col.filter?.descriptor : hasColumnFilters() && !col.width\">\n <ng-container *ngTemplateOutlet=\"col.sort ? sortableColumnTHTemplate : nonSortableColumnTHTemplate\"></ng-container>\n </th>\n }\n }\n @if (hasLastColumn()) {\n <th\n [style.min-width.px]=\"columnLastMinWidth()\"\n pFrozenColumn\n [frozen]=\"metadata.descriptor().actionColumnFrozen ?? areColumnsToggleable()\"\n alignFrozen=\"right\"\n class=\"mng-table-column-custom-last text-right!\">\n @if (areColumnsToggleable()) {\n @defer (on idle) {\n <mng-table-column-toggle [columns]=\"visibleColumns()\" />\n }\n }\n </th>\n }\n </tr>\n }\n @if (hasColumnFilters()) {\n <tr class=\"mng-column-filter-row\">\n <!-- We need the line below, because otherwise p-tableRadioButton shifts the rest of the columns in table -->\n @if (selectionEnabled()) {\n <th style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\"></th>\n }\n @if (rowReorderEnabled()) {\n <th scope=\"col\"></th>\n }\n @if (metadata.descriptor().rowExpandable) {\n <th scope=\"col\"></th>\n }\n @for (col of visibleColumns(); track col.id) {\n <th\n [class]=\"'px-1! ' + col.filter?.descriptor?.columnClassName | mngTableFilterClass: col.filter?.descriptor : hasColumnFilters() && !col.width\"\n [style.width.px]=\"col.width\"\n [style.width.%]=\"col.width ? null : (col.filter?.descriptor?.columnWidth ?? col.descriptor.width ?? null)\"\n [style.min-width.px]=\"col.width ? null : (col.filter?.descriptor?.columnMinWidth ?? col.descriptor.minWidth)\"\n [style.max-width.px]=\"col.width ?? col.descriptor.maxWidth\">\n @if (col.filter && col.filter.descriptor.filterType !== FilterTypeEnum.Component) {\n @defer (on idle) {\n <mng-table-filter [config]=\"col.filter\" [model]=\"metadata.descriptor().model\"></mng-table-filter>\n }\n } @else if (col.filter && col.filter.descriptor.customComponentType) {\n <ng-container [mngComponent]=\"col.filter.descriptor.customComponentType\" [inputs]=\"{descriptor: col.filter.descriptor}\"></ng-container>\n }\n </th>\n }\n @if (hasLastColumn()) {\n <th pFrozenColumn alignFrozen=\"right\" class=\"mng-table-column-custom-last\" [style.min-width.px]=\"columnLastMinWidth()\"></th>\n }\n </tr>\n }\n </ng-template>\n <ng-template #body let-item let-idx=\"rowIndex\" let-expanded=\"expanded\">\n <tr\n [pReorderableRow]=\"idx\"\n [ngClass]=\"\n metadata.descriptor().rowClassName | mngClassMap: metadata.descriptor().rowClassNameMapFn : item | mngLocaleDefaultRowClass: metadata.descriptor() : item\n \">\n @if (selectionEnabled()) {\n @if (selectionMode() === 'multiple') {\n <td style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\">\n <p-tableCheckbox [value]=\"item\"></p-tableCheckbox>\n </td>\n } @else {\n <td style=\"min-width: 36px\" pFrozenColumn [frozen]=\"metadata.descriptor().selectionColumnFrozen ?? true\">\n <p-tableRadioButton [value]=\"item\"></p-tableRadioButton>\n </td>\n }\n }\n @if (metadata.descriptor().rowExpandable) {\n <td>\n @let expandProp = metadata.descriptor().rowExpandableProperty;\n @if (!expandProp || item[expandProp]) {\n <button\n pButton\n type=\"button\"\n [pRowToggler]=\"item\"\n rounded=\"true\"\n text=\"true\"\n class=\"mng-button-sm\"\n [icon]=\"expanded ? 'pi pi-chevron-down' : 'pi pi-chevron-right'\"></button>\n }\n </td>\n }\n @if (rowReorderEnabled()) {\n <td>\n <span class=\"pi pi-bars\" pReorderableRowHandle></span>\n </td>\n }\n @for (col of visibleColumns(); track col.id) {\n <td\n (click)=\"onCellClick($event, col.descriptor, item, idx)\"\n [class]=\"\n col.descriptor.className\n | mngClassMap: col.descriptor.classNameMapFn : item\n | mngTableFilterClass: col.filter?.descriptor : hasColumnFilters() && !col.width\n \"\n [class.clickable]=\"isCellClickEnabled()\"\n [style.width]=\"col.width ? col.width + 'px' : col.descriptor.width + '%'\"\n [style.min-width.px]=\"col.width ? null : col.descriptor.minWidth\"\n [style.max-width.px]=\"col.width ?? col.descriptor.maxWidth\">\n <mng-table-column-value [descriptor]=\"col.descriptor\" [item]=\"item\"></mng-table-column-value>\n </td>\n }\n @if (hasLastColumn()) {\n <td\n class=\"mng-table-column-custom-last justify-end text-right!\"\n [style.min-width.px]=\"columnLastMinWidth()\"\n pFrozenColumn\n alignFrozen=\"right\"\n [frozen]=\"metadata.descriptor().actionColumnFrozen ?? true\">\n @if (columnCustomLastTemplate()) {\n <ng-container\n *ngTemplateOutlet=\"\n columnCustomLastTemplate();\n context: {item: item, index: idx, data: data.data(), totalCount: data.count(), table: this}\n \"></ng-container>\n }\n </td>\n }\n </tr>\n </ng-template>\n <ng-template #expandedrow let-item let-idx=\"rowIndex\">\n @if (metadata.descriptor().rowExpandable) {\n <tr>\n <td></td>\n <td [colSpan]=\"metadata.descriptor().rowExpandableColSpan\">\n @if (metadata.descriptor().rowExpandableComponentType !== undefined) {\n <ng-container [mngComponent]=\"metadata.descriptor().rowExpandableComponentType\" [inputs]=\"{item}\"> </ng-container>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"\n rowExpandTemplate();\n context: {item: item, index: idx, data: data.data(), totalCount: data.count(), table: this}\n \"></ng-container>\n }\n </td>\n </tr>\n }\n </ng-template>\n <ng-template #loadingicon>\n <div class=\"flex flex-col items-center\">\n @if (metadata.descriptor().loadingIcon) {\n <i [class]=\"'text-white text-4xl pi-spin ' + metadata.descriptor().loadingIcon\"></i>\n }\n @if (metadata.descriptor().loadingText) {\n <div class=\"text text-white text-lg font-semibold\" [ngClass]=\"{'mt-3': metadata.descriptor().loadingIcon}\">\n {{ metadata.descriptor().loadingText ?? '' | translate }}\n </div>\n }\n </div>\n </ng-template>\n <ng-template #loadingbody>\n <tr>\n <td [attr.colspan]=\"columnsColspan()\">\n <div class=\"loading-text\"></div>\n <p-skeleton width=\"100%\"></p-skeleton>\n </td>\n </tr>\n </ng-template>\n <ng-template #emptymessage>\n <tr>\n <td [attr.colspan]=\"columnsColspan()\">\n @if (requiredFiltersMissing()) {\n <i class=\"pi pi-exclamation-triangle mr-2\"></i> <strong>{{ 'mngTable.requiredFiltersMissing' | translate }}</strong>\n } @else {\n {{ 'mngTable.noItems' | translate }}\n }\n </td>\n </tr>\n </ng-template>\n @if (footerTemplate()) {\n <ng-template #summary>\n <ng-container *ngTemplateOutlet=\"footerTemplate(); context: {data: data.data(), totalCount: data.count(), table: this}\"></ng-container>\n </ng-template>\n }\n </p-table>\n }\n</div>\n", styles: ["mng-table .p-datatable .p-datatable-header{border-top:0}mng-table .p-datatable:not(.p-datatable-gridlines) .p-datatable-tbody>tr>td{cursor:auto}mng-table .p-datatable:not(.p-datatable-gridlines) .p-datatable-tbody>tr>td.clickable{cursor:pointer}:is(mng-table .p-datatable .p-datatable-thead>tr>th,mng-table .p-datatable .p-datatable-tbody>tr>td):hover mng-table-column-value .help-buttons{display:block}mng-table .p-datatable .p-datatable-thead>tr>th.mng-table-column-custom-last{padding:var(--mng-table-column-head-custom-last, .1rem 1rem)}mng-table .p-datatable .p-datatable-tbody>tr>td{position:relative}mng-table .p-datatable .p-datatable-tbody>tr>td.mng-table-column-custom-last{padding-top:.1rem;padding-bottom:.1rem}mng-table .p-datatable .p-datatable-tbody>tr>td.p-datatable-frozen-column{position:sticky;z-index:1;background:transparent}mng-table .p-datatable.p-datatable-lg .p-datatable-tbody>tr>td.mng-table-column-custom-last{padding:var(--mng-table-column-body-custom-last, .15rem 1rem)}mng-table .p-datatable.p-datatable-sm .p-datatable-tbody>tr>td.mng-table-column-custom-last{padding:var(--mng-table-sm-column-body-custom-last, .05rem 1rem)}mng-table .p-datatable.p-datatable-flex-scrollable .p-datatable-thead>tr>th{overflow:hidden;text-overflow:ellipsis}mng-table .p-datatable.p-datatable-flex-scrollable .p-datatable-tbody>tr>td{overflow:hidden}mng-table .p-datatable .mng-table-row-localization-default-locale{background:var(--p-surface-100)!important}mng-table .mng-table-header>th:not(:first-child):not(:last-child){border-radius:0!important}mng-table .mng-table-header>th:first-child{border-top-right-radius:0!important;border-bottom-right-radius:0!important}mng-table .mng-table-header>th:last-child{border-radius:0!important}mng-table .mng-table-header .mng-table-columns-multiselect{width:36px}mng-table .mng-table-header .mng-table-columns-multiselect .p-multiselect-label-container{width:0}mng-table.mng-table-no-header p-datatable .p-datatable-header{display:none}mng-table.mng-table-header-compact .p-datatable-header{padding:var(--mng-table-header-compact-padding, 0 0 .5rem 0)!important}\n"] }]
|
|
2661
|
+
}], ctorParameters: () => [], propDecorators: { descriptorInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "descriptor", required: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], result: [{ type: i0.Input, args: [{ isSignal: true, alias: "result", required: false }] }], loadingInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], dataProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataProvider", required: false }] }], useQueryParams: [{ type: i0.Input, args: [{ isSignal: true, alias: "useQueryParams", required: false }] }], cellClickEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellClickEnabled", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selectionEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionEnabled", required: false }] }], rowReorderEnabledInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowReorderEnabled", required: false }] }], columnLastMinWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnLastMinWidth", required: false }] }], globalFilterFieldsInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalFilterFields", required: false }] }], tableLoad: [{ type: i0.Output, args: ["tableLoad"] }], cellClick: [{ type: i0.Output, args: ["cellClick"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], rowReorder: [{ type: i0.Output, args: ["rowReorder"] }], templates: [{ type: i0.Input, args: [{ isSignal: true, alias: "templates", required: false }] }], contentTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TableTemplateDirective), { isSignal: true }] }], primeTable: [{ type: i0.ViewChild, args: [i0.forwardRef(() => Table), { isSignal: true }] }] } }) });
|
|
2662
|
+
|
|
2663
|
+
/**
|
|
2664
|
+
* Prepares providers for usage of the tableview functionalities.
|
|
2665
|
+
*
|
|
2666
|
+
* @returns {CommonsFeature} The `CommonsFeature` object with the layout configuration.
|
|
2667
|
+
*/
|
|
2668
|
+
function withTable(config) {
|
|
2669
|
+
return {
|
|
2670
|
+
type: CommonsFeatureTypeEnum.Table,
|
|
2671
|
+
providers: [
|
|
2672
|
+
{
|
|
2673
|
+
provide: COMMONS_TABLE_FEATURE_CONFIG_IT,
|
|
2674
|
+
useValue: config
|
|
2675
|
+
}
|
|
2676
|
+
]
|
|
2677
|
+
};
|
|
2678
|
+
}
|
|
2679
|
+
/**
|
|
2680
|
+
* Provides a list of providers for configuring a table feature. Useful for lazy-loading table chunk in child (lazy loaded routes).
|
|
2681
|
+
*
|
|
2682
|
+
* @param {TableFeatureConfig} [config] - An optional configuration object for the table feature.
|
|
2683
|
+
*/
|
|
2684
|
+
function provideTableChild(config) {
|
|
2685
|
+
return [
|
|
2686
|
+
{
|
|
2687
|
+
provide: COMMONS_TABLE_FEATURE_CONFIG_IT,
|
|
2688
|
+
useValue: config
|
|
2689
|
+
}
|
|
2690
|
+
];
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
// components
|
|
2694
|
+
|
|
2695
|
+
/**
|
|
2696
|
+
* Generated bundle index. Do not edit.
|
|
2697
|
+
*/
|
|
2698
|
+
|
|
2699
|
+
export { ADataListService as A, COMMONS_TABLE_FEATURE_CONFIG_IT as C, FilterService as F, LocaleDefaultRowClassPipe as L, TableMetadataService as T, TablePreferencesService as a, TableFilterComponent as b, TableColumnValueComponent as c, TableFilterActiveTagComponent as d, TableFilterFormComponent as e, TableHeaderWithFiltersComponent as f, TableComponent as g, TableTemplateDirective as h, filterGenerateMatchModeOptions as i, filterGetDefaultMatchMode as j, filterSetStateOnChange as k, filterSetStateOnDisplayChange as l, filterAreDatesEqual as m, filterApplySerializationConfigToCmp as n, filterAdjustDisplayValueOnMatchModeChange as o, filterGetDateConfig as p, filterGetNumberConfig as q, createFilterDescriptorsFromGeneric as r, isFilterValueBlank as s, tableNotificationError as t, generateTableLayoutPrefsKey as u, FilterValuePipe as v, TableFilterClassPipe as w, TableDataService as x, withTable as y, provideTableChild as z };
|
|
2700
|
+
//# sourceMappingURL=mediusinc-mng-commons-table-mediusinc-mng-commons-table-BLuM5Kpu.mjs.map
|