@sdcorejs/angular 20.0.7 → 20.0.9
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/README.md +8 -2
- package/assets/STYLE-GUIDE.md +13 -0
- package/components/autoid-inspector/index.d.ts +47 -137
- package/components/table/index.d.ts +5 -9
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +2 -3
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +195 -25
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-badge.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-button.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +5 -6
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-editor.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +4 -4
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-inform.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-modal-resizable.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-modal.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-operator.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-org-chart.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-preview.mjs +3 -3
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +8 -8
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-section.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +6 -4
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-table.mjs +772 -810
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-tree.mjs +2 -2
- package/fesm2022/sdcorejs-angular-components-tree.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +7 -8
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +4 -5
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +3 -3
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +4 -4
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +4 -4
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +16 -9
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-date.mjs +5 -6
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +5 -6
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs +2 -2
- package/fesm2022/sdcorejs-angular-forms-inline-text.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +5 -6
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-input.mjs +3 -3
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +3 -4
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-select.mjs +2 -2
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-switch.mjs +3 -4
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +5 -7
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +2 -3
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-api.mjs +1 -2
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -1
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +2 -2
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -1
- package/forms/date-range/index.d.ts +2 -0
- package/forms/input-number/index.d.ts +0 -1
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ import * as i1$1 from '@sdcorejs/angular/services';
|
|
|
11
11
|
import { SdExcelService, SdNotifyService } from '@sdcorejs/angular/services';
|
|
12
12
|
import { Subject, fromEvent, Subscription, isObservable, firstValueFrom } from 'rxjs';
|
|
13
13
|
import { debounceTime, startWith, map, switchMap } from 'rxjs/operators';
|
|
14
|
-
import
|
|
14
|
+
import { DateUtilities, StringUtilities } from '@sdcorejs/angular/utilities';
|
|
15
15
|
import { CdkTableModule, CdkColumnDef } from '@angular/cdk/table';
|
|
16
16
|
import * as i11 from '@angular/cdk/drag-drop';
|
|
17
17
|
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
@@ -34,7 +34,7 @@ import { SdQuickAction } from '@sdcorejs/angular/components/quick-action';
|
|
|
34
34
|
import { SdTooltipDirective, SdScrollDirective, SdDesktopDirective, SdMobileDirective, SdHoverCopyDirective } from '@sdcorejs/angular/directives';
|
|
35
35
|
import { SdSafeHtmlPipe, SdFormatNumberPipe } from '@sdcorejs/angular/pipes';
|
|
36
36
|
import { BrowserUtilities, Utilities } from '@sdcorejs/utils/fns';
|
|
37
|
-
import { DateUtilities, ArrayUtilities, NumberUtilities } from '@sdcorejs/angular/utilities/extensions';
|
|
37
|
+
import { DateUtilities as DateUtilities$1, ArrayUtilities, NumberUtilities } from '@sdcorejs/angular/utilities/extensions';
|
|
38
38
|
import { SdBadge } from '@sdcorejs/angular/components/badge';
|
|
39
39
|
import { SdOperator } from '@sdcorejs/angular/components/operator';
|
|
40
40
|
import { SdInput, SdInputNumber, SdSelect, SdDate, SdDatetime, SdDateRange as SdDateRange$1, SdCheckbox, SdSwitch } from '@sdcorejs/angular/forms';
|
|
@@ -51,7 +51,6 @@ import * as i3 from '@angular/material/button';
|
|
|
51
51
|
import { MatButtonModule } from '@angular/material/button';
|
|
52
52
|
import * as i1$2 from '@angular/material/tooltip';
|
|
53
53
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
54
|
-
import { StringUtilities, DateUtilities as DateUtilities$1 } from '@sdcorejs/angular/utilities';
|
|
55
54
|
import * as i5 from '@angular/material/chips';
|
|
56
55
|
import { MatChipsModule } from '@angular/material/chips';
|
|
57
56
|
|
|
@@ -163,6 +162,242 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
163
162
|
}]
|
|
164
163
|
}], propDecorators: { sdTableTitleDef: [{ type: i0.Input, args: [{ isSignal: true, alias: "sdTableTitleDef", required: true }] }] } });
|
|
165
164
|
|
|
165
|
+
const SdConvertToPagingReq = (filterRequest, args) => {
|
|
166
|
+
const { externalFilters, columns, fieldMapping } = args;
|
|
167
|
+
const req = {
|
|
168
|
+
filters: [],
|
|
169
|
+
orders: args?.orders || [],
|
|
170
|
+
pageNumber: filterRequest.pageNumber,
|
|
171
|
+
pageSize: filterRequest.pageSize,
|
|
172
|
+
};
|
|
173
|
+
const { filters } = req;
|
|
174
|
+
const { rawExternalFilter, rawColumnFilter, columnOperator, orderBy, orderDirection } = filterRequest;
|
|
175
|
+
// Xử lý external filter
|
|
176
|
+
for (const externalFilter of externalFilters || []) {
|
|
177
|
+
const value = rawExternalFilter?.[externalFilter.field];
|
|
178
|
+
const field = fieldMapping?.[externalFilter.field] || externalFilter.field;
|
|
179
|
+
// Nếu có giá trị thì mới xử lý filter
|
|
180
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
181
|
+
if (externalFilter.type === 'string') {
|
|
182
|
+
if (externalFilter.defaultOperator === 'EQUAL' && typeof value === 'string' && value.includes(',')) {
|
|
183
|
+
filters.push({
|
|
184
|
+
field,
|
|
185
|
+
operator: 'IN',
|
|
186
|
+
data: value.split(',').map(val => val.trim()),
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
filters.push({
|
|
191
|
+
field,
|
|
192
|
+
operator: externalFilter.defaultOperator || 'CONTAIN',
|
|
193
|
+
data: value,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else if (externalFilter.type === 'boolean') {
|
|
198
|
+
filters.push({
|
|
199
|
+
field,
|
|
200
|
+
operator: 'EQUAL',
|
|
201
|
+
data: value === true || value === 1 || value === 'true' || value === '1',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
else if (externalFilter.type === 'daterange') {
|
|
205
|
+
if (typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
206
|
+
if (value?.from) {
|
|
207
|
+
filters.push({
|
|
208
|
+
field,
|
|
209
|
+
operator: 'GREATER_OR_EQUAL',
|
|
210
|
+
data: DateUtilities.begin(value?.from).toISOString(),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
if (value?.to) {
|
|
214
|
+
filters.push({
|
|
215
|
+
field,
|
|
216
|
+
operator: 'LESS_THAN',
|
|
217
|
+
data: DateUtilities.begin(DateUtilities.addDays(value?.to, 1)).toISOString(),
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else if (externalFilter.type === 'date' || externalFilter.type === 'datetime') {
|
|
223
|
+
if (typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
224
|
+
if (value?.from) {
|
|
225
|
+
filters.push({
|
|
226
|
+
field,
|
|
227
|
+
operator: 'GREATER_OR_EQUAL',
|
|
228
|
+
data: DateUtilities.begin(value?.from).toISOString(),
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (value?.to) {
|
|
232
|
+
filters.push({
|
|
233
|
+
field,
|
|
234
|
+
operator: 'LESS_THAN',
|
|
235
|
+
data: DateUtilities.begin(DateUtilities.addDays(value?.to, 1)).toISOString(),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else if (DateUtilities.isDate(value)) {
|
|
240
|
+
if (externalFilter.type === 'date') {
|
|
241
|
+
if (externalFilter.defaultOperator === 'GREATER_OR_EQUAL') {
|
|
242
|
+
filters.push({
|
|
243
|
+
field,
|
|
244
|
+
operator: 'GREATER_OR_EQUAL',
|
|
245
|
+
data: DateUtilities.begin(value).toISOString(),
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
if (externalFilter.defaultOperator === 'LESS_OR_EQUAL') {
|
|
249
|
+
filters.push({
|
|
250
|
+
field,
|
|
251
|
+
operator: 'LESS_THAN',
|
|
252
|
+
data: DateUtilities.begin(DateUtilities.addDays(value, 1)).toISOString(),
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
if (externalFilter.defaultOperator === 'GREATER_OR_EQUAL') {
|
|
258
|
+
filters.push({
|
|
259
|
+
field,
|
|
260
|
+
operator: 'GREATER_OR_EQUAL',
|
|
261
|
+
data: new Date(value).toISOString(),
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
if (externalFilter.defaultOperator === 'LESS_OR_EQUAL') {
|
|
265
|
+
filters.push({
|
|
266
|
+
field,
|
|
267
|
+
operator: 'LESS_OR_EQUAL',
|
|
268
|
+
data: new Date(value).toISOString(),
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
if (Array.isArray(value)) {
|
|
276
|
+
if (value.length) {
|
|
277
|
+
filters.push({
|
|
278
|
+
field,
|
|
279
|
+
operator: 'IN',
|
|
280
|
+
data: value,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else if (typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
285
|
+
if (value?.from) {
|
|
286
|
+
filters.push({
|
|
287
|
+
field,
|
|
288
|
+
operator: 'GREATER_OR_EQUAL',
|
|
289
|
+
data: DateUtilities.begin(value?.from).toISOString(),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
if (value?.to) {
|
|
293
|
+
filters.push({
|
|
294
|
+
field,
|
|
295
|
+
operator: 'LESS_THAN',
|
|
296
|
+
data: DateUtilities.begin(DateUtilities.addDays(value?.to, 1)).toISOString(),
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
filters.push({
|
|
302
|
+
field,
|
|
303
|
+
operator: externalFilter.defaultOperator || 'EQUAL',
|
|
304
|
+
data: value,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// Xử lý column filter
|
|
311
|
+
for (const column of columns || []) {
|
|
312
|
+
const value = rawColumnFilter?.[column.field];
|
|
313
|
+
const field = fieldMapping?.[column.field] || column.field;
|
|
314
|
+
const operator = columnOperator?.[column.field] || column.filter?.operator?.default;
|
|
315
|
+
// Nếu có giá trị thì mới xử lý filter
|
|
316
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
317
|
+
if (column.type === 'string') {
|
|
318
|
+
filters.push({
|
|
319
|
+
field,
|
|
320
|
+
operator: operator || 'CONTAIN',
|
|
321
|
+
data: value,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
else if (column.type === 'boolean') {
|
|
325
|
+
filters.push({
|
|
326
|
+
field,
|
|
327
|
+
operator: 'EQUAL',
|
|
328
|
+
data: value === true || value === 1 || value === 'true' || value === '1',
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
else if (column.type === 'date' || column.type === 'datetime') {
|
|
332
|
+
if (typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
333
|
+
if (value?.from && value?.to) {
|
|
334
|
+
filters.push({
|
|
335
|
+
field,
|
|
336
|
+
operator: 'BETWEEN',
|
|
337
|
+
data: {
|
|
338
|
+
from: DateUtilities.begin(value?.from).toISOString(),
|
|
339
|
+
to: DateUtilities.end(value?.to).toISOString(),
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
else if (value?.from) {
|
|
344
|
+
filters.push({
|
|
345
|
+
field,
|
|
346
|
+
operator: 'GREATER_OR_EQUAL',
|
|
347
|
+
data: DateUtilities.begin(value?.from).toISOString(),
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
else if (value?.to) {
|
|
351
|
+
filters.push({
|
|
352
|
+
field,
|
|
353
|
+
operator: 'LESS_THAN',
|
|
354
|
+
data: DateUtilities.begin(DateUtilities.addDays(value?.to, 1)).toISOString(),
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
if (DateUtilities.isDate(value)) {
|
|
360
|
+
filters.push({
|
|
361
|
+
field,
|
|
362
|
+
operator: 'BETWEEN',
|
|
363
|
+
data: {
|
|
364
|
+
from: DateUtilities.begin(value).toISOString(),
|
|
365
|
+
to: DateUtilities.end(value).toISOString(),
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
if (Array.isArray(value)) {
|
|
373
|
+
if (value.length) {
|
|
374
|
+
filters.push({
|
|
375
|
+
field,
|
|
376
|
+
operator: 'IN',
|
|
377
|
+
data: value,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
filters.push({
|
|
383
|
+
field,
|
|
384
|
+
operator: operator || 'EQUAL',
|
|
385
|
+
data: value,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// Xử lý orders
|
|
392
|
+
if (orderBy && orderDirection) {
|
|
393
|
+
req.orders.push({
|
|
394
|
+
field: orderBy,
|
|
395
|
+
direction: orderDirection,
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
return req;
|
|
399
|
+
};
|
|
400
|
+
|
|
166
401
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
167
402
|
class ColumnTitleComponent {
|
|
168
403
|
column = input.required(...(ngDevMode ? [{ debugName: "column" }] : []));
|
|
@@ -235,8 +470,6 @@ class ColumnFilterComponent {
|
|
|
235
470
|
}, ...(ngDevMode ? [{ debugName: "operators" }] : []));
|
|
236
471
|
// Chỉ các Operator value cho phép — truyền vào <sd-operator [operators]>.
|
|
237
472
|
operatorValues = computed(() => this.operators().map(o => o.value), ...(ngDevMode ? [{ debugName: "operatorValues" }] : []));
|
|
238
|
-
// Margin wrapper operator: số + đang chọn operator → thêm mb-4 (canh baseline với sd-input-number).
|
|
239
|
-
operatorWrapperClass = computed(() => (this.column()?.type === 'number' && this.operator() ? 'mb-4 mr-2' : 'mr-2'), ...(ngDevMode ? [{ debugName: "operatorWrapperClass" }] : []));
|
|
240
473
|
// Items cho sd-select khi column type = values / lazy-values
|
|
241
474
|
items = computed(() => {
|
|
242
475
|
const col = this.column();
|
|
@@ -279,11 +512,11 @@ class ColumnFilterComponent {
|
|
|
279
512
|
// Blur input: commit giá trị KHÔNG trigger reload.
|
|
280
513
|
onFilterCommit = () => this.filterCommit.emit();
|
|
281
514
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ColumnFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
282
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ColumnFilterComponent, isStandalone: true, selector: "column-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, columnFilter: { classPropertyName: "columnFilter", publicName: "columnFilter", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, operator: { classPropertyName: "operator", publicName: "operator", isSignal: true, isRequired: false, transformFunction: null }, isMobile: { classPropertyName: "isMobile", publicName: "isMobile", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { operator: "operatorChange", filterChange: "filterChange", filterCommit: "filterCommit" }, ngImport: i0, template: "@let _column = column();\n@let _columnFilter = columnFilter();\n@let _autoId = autoId();\n@let _templateRef = templateRef();\n@let _operators = operators();\n@let _items = items();\n@let _label = label();\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\n\n<div class=\"d-flex c-inline-column align-items-end\" style=\"width: 100%; max-width: 100%\">\n @if (\n _column.type === 'string' ||\n _column.type === 'number' ||\n _column.type === 'boolean' ||\n _column.type === 'values' ||\n _column.type === 'lazy-values' ||\n _column.type === 'date' ||\n _column.type === 'datetime' ||\n _column.type === 'time'\n ) {\n <!-- Operator filter -->\n @if (_operators.length) {\n <div class=\"d-flex align-items-center\" [ngClass]=\"operatorWrapperClass()\">\n <sd-operator [(model)]=\"operator\" [operators]=\"operatorValues()\" />\n </div>\n }\n\n <!-- N\u1EBFu filter nh\u1EADn v\u00E0o template -->\n @if (_templateRef) {\n <ng-container *ngTemplateOutlet=\"_templateRef; context: _context\"></ng-container>\n }\n <!-- M\u1EB7c \u0111\u1ECBnh theo type v\u00E0 gi\u00E1 tr\u1ECB values defined c\u1EE7a column -->\n @else {\n @if (_column.type === 'string') {\n <sd-input\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n type=\"text\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (keyupEnter)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-input>\n } @else if (_column.type === 'number') {\n @if (!_column.filter?.type) {\n <sd-input-number\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (keyupEnter)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-input-number>\n } @else if (_column.filter?.type === 'split-number') {\n <ng-container\n *ngTemplateOutlet=\"splitNumberTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\n </ng-container>\n }\n } @else if (_column.type === 'boolean') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"[\n { value: '1', display: _column.option?.displayOnTrue || 'True' },\n { value: '0', display: _column.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n <ng-template sdItemDef let-item=\"item\">\n @if (item.value === '1') {\n <sd-badge color=\"success\" [title]=\"_column.option?.displayOnTrue || 'True'\"> </sd-badge>\n } @else {\n <sd-badge color=\"error\" [title]=\"_column.option?.displayOnFalse || 'False'\"> </sd-badge>\n }\n </ng-template>\n </sd-select>\n } @else if (_column.type === 'values') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"_items\"\n [valueField]=\"_column.option.valueField\"\n [displayField]=\"_column.option.displayField\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\n hideInlineError>\n </sd-select>\n } @else if (_column.type === 'lazy-values') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"_items\"\n [valueField]=\"_column.option.valueField\"\n [displayField]=\"_column.option.displayField\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\n hideInlineError>\n </sd-select>\n } @else if (_column.type === 'date' || _column.type === 'datetime' || _column.type === 'time') {\n @if (!_column.filter?.type || _column.filter?.type === 'daterange') {\n <sd-date-range\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-date-range>\n } @else if (_column.filter?.type === 'date') {\n <sd-date\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-date>\n } @else if (_column.filter?.type === 'split-date') {\n <ng-container\n *ngTemplateOutlet=\"splitDateTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\n </ng-container>\n }\n }\n }\n } @else {\n <sd-input [autoId]=\"_autoId\" style=\"flex: 1 1 0%; min-width: 0\" type=\"text\" size=\"sm\" disabled></sd-input>\n }\n</div>\n\n<!-- ================================================ -->\n<!-- Split from/to templates (\u0111\u01B0a xu\u1ED1ng cu\u1ED1i file) -->\n<!-- ================================================ -->\n<ng-template #splitNumberTpl let-field=\"field\" let-disabled=\"disabled\">\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\n <sd-input-number\n [autoId]=\"_autoId + '-from'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[field].from\"\n (sdChange)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-input-number>\n <div class=\"mx-4\">-</div>\n <sd-input-number\n [autoId]=\"_autoId + '-to'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [(model)]=\"_columnFilter[field].to\"\n (sdChange)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-input-number>\n </div>\n</ng-template>\n\n<ng-template #splitDateTpl let-field=\"field\" let-disabled=\"disabled\">\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\n <sd-date\n [autoId]=\"_autoId + '-from'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[field].from\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-date>\n <div class=\"mx-4\">-</div>\n <sd-date\n [autoId]=\"_autoId + '-to'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [(model)]=\"_columnFilter[field].to\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-date>\n </div>\n</ng-template>\n", styles: [":host ::ng-deep .c-inline-column .mat-mdc-text-field-wrapper{background-color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SdOperator, selector: "sd-operator", inputs: ["model", "operators", "disabled", "autoId"], outputs: ["modelChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdBadge, selector: "sd-badge", inputs: ["type", "color", "primary", "secondary", "success", "info", "warning", "error", "fontSet", "title", "description", "tooltip", "icon", "size"], outputs: ["click"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
515
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ColumnFilterComponent, isStandalone: true, selector: "column-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, columnFilter: { classPropertyName: "columnFilter", publicName: "columnFilter", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, operator: { classPropertyName: "operator", publicName: "operator", isSignal: true, isRequired: false, transformFunction: null }, isMobile: { classPropertyName: "isMobile", publicName: "isMobile", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { operator: "operatorChange", filterChange: "filterChange", filterCommit: "filterCommit" }, ngImport: i0, template: "@let _column = column();\n@let _columnFilter = columnFilter();\n@let _autoId = autoId();\n@let _templateRef = templateRef();\n@let _operators = operators();\n@let _items = items();\n@let _label = label();\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\n\n<div class=\"d-flex c-inline-column align-items-center\" style=\"width: 100%; max-width: 100%\">\n @if (\n _column.type === 'string' ||\n _column.type === 'number' ||\n _column.type === 'boolean' ||\n _column.type === 'values' ||\n _column.type === 'lazy-values' ||\n _column.type === 'date' ||\n _column.type === 'datetime' ||\n _column.type === 'time'\n ) {\n <!-- Operator filter -->\n @if (_operators.length) {\n <sd-operator class=\"mr-4\" [(model)]=\"operator\" [operators]=\"operatorValues()\" />\n }\n\n <!-- N\u1EBFu filter nh\u1EADn v\u00E0o template -->\n @if (_templateRef) {\n <ng-container *ngTemplateOutlet=\"_templateRef; context: _context\"></ng-container>\n }\n <!-- M\u1EB7c \u0111\u1ECBnh theo type v\u00E0 gi\u00E1 tr\u1ECB values defined c\u1EE7a column -->\n @else {\n @if (_column.type === 'string') {\n <sd-input\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n type=\"text\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (keyupEnter)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-input>\n } @else if (_column.type === 'number') {\n @if (!_column.filter?.type) {\n <sd-input-number\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (keyupEnter)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-input-number>\n } @else if (_column.filter?.type === 'split-number') {\n <ng-container *ngTemplateOutlet=\"splitNumberTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\n </ng-container>\n }\n } @else if (_column.type === 'boolean') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"[\n { value: '1', display: _column.option?.displayOnTrue || 'True' },\n { value: '0', display: _column.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n <ng-template sdItemDef let-item=\"item\">\n @if (item.value === '1') {\n <sd-badge color=\"success\" [title]=\"_column.option?.displayOnTrue || 'True'\"> </sd-badge>\n } @else {\n <sd-badge color=\"error\" [title]=\"_column.option?.displayOnFalse || 'False'\"> </sd-badge>\n }\n </ng-template>\n </sd-select>\n } @else if (_column.type === 'values') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"_items\"\n [valueField]=\"_column.option.valueField\"\n [displayField]=\"_column.option.displayField\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\n hideInlineError>\n </sd-select>\n } @else if (_column.type === 'lazy-values') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"_items\"\n [valueField]=\"_column.option.valueField\"\n [displayField]=\"_column.option.displayField\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\n hideInlineError>\n </sd-select>\n } @else if (_column.type === 'date' || _column.type === 'datetime' || _column.type === 'time') {\n @if (!_column.filter?.type || _column.filter?.type === 'daterange') {\n <sd-date-range\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-date-range>\n } @else if (_column.filter?.type === 'date') {\n <sd-date\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-date>\n } @else if (_column.filter?.type === 'split-date') {\n <ng-container *ngTemplateOutlet=\"splitDateTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\n </ng-container>\n }\n }\n }\n } @else {\n <sd-input [autoId]=\"_autoId\" style=\"flex: 1 1 0%; min-width: 0\" type=\"text\" size=\"sm\" disabled></sd-input>\n }\n</div>\n\n<!-- ================================================ -->\n<!-- Split from/to templates (\u0111\u01B0a xu\u1ED1ng cu\u1ED1i file) -->\n<!-- ================================================ -->\n<ng-template #splitNumberTpl let-field=\"field\" let-disabled=\"disabled\">\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\n <sd-input-number\n [autoId]=\"_autoId + '-from'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[field].from\"\n (sdChange)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-input-number>\n <div class=\"mx-4\">-</div>\n <sd-input-number\n [autoId]=\"_autoId + '-to'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [(model)]=\"_columnFilter[field].to\"\n (sdChange)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-input-number>\n </div>\n</ng-template>\n\n<ng-template #splitDateTpl let-field=\"field\" let-disabled=\"disabled\">\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\n <sd-date\n [autoId]=\"_autoId + '-from'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[field].from\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-date>\n <div class=\"mx-4\">-</div>\n <sd-date\n [autoId]=\"_autoId + '-to'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [(model)]=\"_columnFilter[field].to\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-date>\n </div>\n</ng-template>\n", styles: [":host ::ng-deep .c-inline-column .mat-mdc-text-field-wrapper{background-color:#fff}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SdOperator, selector: "sd-operator", inputs: ["model", "operators", "disabled", "autoId"], outputs: ["modelChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdBadge, selector: "sd-badge", inputs: ["type", "color", "primary", "secondary", "success", "info", "warning", "error", "fontSet", "title", "description", "tooltip", "icon", "size"], outputs: ["click"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
283
516
|
}
|
|
284
517
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ColumnFilterComponent, decorators: [{
|
|
285
518
|
type: Component,
|
|
286
|
-
args: [{ selector: 'column-filter', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, SdOperator, SdInput, SdInputNumber, SdSelect, SdDate, SdDateRange, SdBadge], template: "@let _column = column();\n@let _columnFilter = columnFilter();\n@let _autoId = autoId();\n@let _templateRef = templateRef();\n@let _operators = operators();\n@let _items = items();\n@let _label = label();\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\n\n<div class=\"d-flex c-inline-column align-items-
|
|
519
|
+
args: [{ selector: 'column-filter', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, SdOperator, SdInput, SdInputNumber, SdSelect, SdDate, SdDateRange, SdBadge], template: "@let _column = column();\n@let _columnFilter = columnFilter();\n@let _autoId = autoId();\n@let _templateRef = templateRef();\n@let _operators = operators();\n@let _items = items();\n@let _label = label();\n@let _context = { columnFilter: _columnFilter, autoId: _autoId };\n\n<div class=\"d-flex c-inline-column align-items-center\" style=\"width: 100%; max-width: 100%\">\n @if (\n _column.type === 'string' ||\n _column.type === 'number' ||\n _column.type === 'boolean' ||\n _column.type === 'values' ||\n _column.type === 'lazy-values' ||\n _column.type === 'date' ||\n _column.type === 'datetime' ||\n _column.type === 'time'\n ) {\n <!-- Operator filter -->\n @if (_operators.length) {\n <sd-operator class=\"mr-4\" [(model)]=\"operator\" [operators]=\"operatorValues()\" />\n }\n\n <!-- N\u1EBFu filter nh\u1EADn v\u00E0o template -->\n @if (_templateRef) {\n <ng-container *ngTemplateOutlet=\"_templateRef; context: _context\"></ng-container>\n }\n <!-- M\u1EB7c \u0111\u1ECBnh theo type v\u00E0 gi\u00E1 tr\u1ECB values defined c\u1EE7a column -->\n @else {\n @if (_column.type === 'string') {\n <sd-input\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n type=\"text\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (keyupEnter)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-input>\n } @else if (_column.type === 'number') {\n @if (!_column.filter?.type) {\n <sd-input-number\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (keyupEnter)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-input-number>\n } @else if (_column.filter?.type === 'split-number') {\n <ng-container *ngTemplateOutlet=\"splitNumberTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\n </ng-container>\n }\n } @else if (_column.type === 'boolean') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"[\n { value: '1', display: _column.option?.displayOnTrue || 'True' },\n { value: '0', display: _column.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n <ng-template sdItemDef let-item=\"item\">\n @if (item.value === '1') {\n <sd-badge color=\"success\" [title]=\"_column.option?.displayOnTrue || 'True'\"> </sd-badge>\n } @else {\n <sd-badge color=\"error\" [title]=\"_column.option?.displayOnFalse || 'False'\"> </sd-badge>\n }\n </ng-template>\n </sd-select>\n } @else if (_column.type === 'values') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"_items\"\n [valueField]=\"_column.option.valueField\"\n [displayField]=\"_column.option.displayField\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\n hideInlineError>\n </sd-select>\n } @else if (_column.type === 'lazy-values') {\n <sd-select\n minWidthPanel=\"200px\"\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n [style.width]=\"'100%'\"\n size=\"sm\"\n [label]=\"_label\"\n [items]=\"_items\"\n [valueField]=\"_column.option.valueField\"\n [displayField]=\"_column.option.displayField\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n [multiple]=\"_column.option.selection === 'MULTIPLE'\"\n hideInlineError>\n </sd-select>\n } @else if (_column.type === 'date' || _column.type === 'datetime' || _column.type === 'time') {\n @if (!_column.filter?.type || _column.filter?.type === 'daterange') {\n <sd-date-range\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-date-range>\n } @else if (_column.filter?.type === 'date') {\n <sd-date\n [autoId]=\"_autoId\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[_column.field]\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"_column.filter?.disabled\"\n hideInlineError>\n </sd-date>\n } @else if (_column.filter?.type === 'split-date') {\n <ng-container *ngTemplateOutlet=\"splitDateTpl; context: { field: _column.field, disabled: _column.filter?.disabled }\">\n </ng-container>\n }\n }\n }\n } @else {\n <sd-input [autoId]=\"_autoId\" style=\"flex: 1 1 0%; min-width: 0\" type=\"text\" size=\"sm\" disabled></sd-input>\n }\n</div>\n\n<!-- ================================================ -->\n<!-- Split from/to templates (\u0111\u01B0a xu\u1ED1ng cu\u1ED1i file) -->\n<!-- ================================================ -->\n<ng-template #splitNumberTpl let-field=\"field\" let-disabled=\"disabled\">\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\n <sd-input-number\n [autoId]=\"_autoId + '-from'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[field].from\"\n (sdChange)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-input-number>\n <div class=\"mx-4\">-</div>\n <sd-input-number\n [autoId]=\"_autoId + '-to'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n size=\"sm\"\n [(model)]=\"_columnFilter[field].to\"\n (sdChange)=\"onFilterChange()\"\n (sdBlur)=\"onFilterCommit()\"\n (cleared)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-input-number>\n </div>\n</ng-template>\n\n<ng-template #splitDateTpl let-field=\"field\" let-disabled=\"disabled\">\n <div class=\"d-flex align-items-center\" style=\"flex: 1 1 0%; min-width: 0\">\n <sd-date\n [autoId]=\"_autoId + '-from'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [label]=\"_label\"\n [(model)]=\"_columnFilter[field].from\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-date>\n <div class=\"mx-4\">-</div>\n <sd-date\n [autoId]=\"_autoId + '-to'\"\n style=\"flex: 1 1 0%; min-width: 0\"\n type=\"date\"\n size=\"sm\"\n [(model)]=\"_columnFilter[field].to\"\n (sdChange)=\"onFilterChange()\"\n [disabled]=\"disabled\"\n hideInlineError>\n </sd-date>\n </div>\n</ng-template>\n", styles: [":host ::ng-deep .c-inline-column .mat-mdc-text-field-wrapper{background-color:#fff}\n"] }]
|
|
287
520
|
}], ctorParameters: () => [], propDecorators: { autoIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoId", required: false }] }], column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], columnFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "columnFilter", required: false }] }], cacheValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "cacheValues", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], operator: [{ type: i0.Input, args: [{ isSignal: true, alias: "operator", required: false }] }, { type: i0.Output, args: ["operatorChange"] }], isMobile: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMobile", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], filterCommit: [{ type: i0.Output, args: ["filterCommit"] }] } });
|
|
288
521
|
|
|
289
522
|
// Đối với filter loại values, items có thể là 1 mảng, có thể là 1 hàm, do đó cần xử lý nếu là hàm có thể xử lý gọi API
|
|
@@ -336,7 +569,7 @@ const getChildrenFromData = (data, option) => {
|
|
|
336
569
|
* mặc định nhánh chưa nạp).
|
|
337
570
|
*/
|
|
338
571
|
const resolveDefaultExpanded = (level, option) => {
|
|
339
|
-
const def = option?.loadType === 'static' ? option.defaultExpanded ?? false : false;
|
|
572
|
+
const def = option?.loadType === 'static' ? (option.defaultExpanded ?? false) : false;
|
|
340
573
|
if (def === true)
|
|
341
574
|
return true;
|
|
342
575
|
if (def === false)
|
|
@@ -392,6 +625,48 @@ const subtreeMatches = (data, predicate, option, visited = new Set()) => {
|
|
|
392
625
|
* bị mất khi từ khoá search đổi. Đây là bước "prune" của tính năng search-con.
|
|
393
626
|
*/
|
|
394
627
|
const filterMatchingChildren = (children, predicate, option) => children.filter(child => subtreeMatches(child, predicate, option));
|
|
628
|
+
const getVisibleChildrenData = (data, option, predicate) => {
|
|
629
|
+
const children = getChildrenFromData(data, option);
|
|
630
|
+
return predicate ? filterMatchingChildren(children, predicate, option) : children;
|
|
631
|
+
};
|
|
632
|
+
const saveTreeExpandState = (rows, expandState) => {
|
|
633
|
+
for (const row of rows) {
|
|
634
|
+
if (row.meta.tree?.isExpanded) {
|
|
635
|
+
expandState.set(row.meta.id, true);
|
|
636
|
+
}
|
|
637
|
+
const children = row.meta.tree?.childItems;
|
|
638
|
+
if (children?.length) {
|
|
639
|
+
saveTreeExpandState(children, expandState);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
const clearTreeChildCache = (rows) => {
|
|
644
|
+
for (const row of rows) {
|
|
645
|
+
const children = row.meta.tree?.childItems;
|
|
646
|
+
if (children?.length) {
|
|
647
|
+
clearTreeChildCache(children);
|
|
648
|
+
row.meta.tree.childItems = undefined;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
const initTreeMeta = (rows, option, args = {}) => {
|
|
653
|
+
const { expandState, treeSearchPredicate, level = 0, parentId } = args;
|
|
654
|
+
const searchActive = !!treeSearchPredicate;
|
|
655
|
+
for (const row of rows) {
|
|
656
|
+
const saved = expandState?.get(row.meta.id);
|
|
657
|
+
const hasChildren = searchActive
|
|
658
|
+
? getVisibleChildrenData(row.data, option, treeSearchPredicate).length > 0
|
|
659
|
+
: resolveHasChildren(row, option);
|
|
660
|
+
row.meta.tree = {
|
|
661
|
+
...row.meta.tree,
|
|
662
|
+
level,
|
|
663
|
+
parentId,
|
|
664
|
+
hasChildren,
|
|
665
|
+
isExpanded: searchActive ? hasChildren : (saved ?? resolveDefaultExpanded(level, option)),
|
|
666
|
+
isExpanding: false,
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
};
|
|
395
670
|
const flattenTree = (roots, option, visited = new Set()) => {
|
|
396
671
|
if (!option)
|
|
397
672
|
return roots;
|
|
@@ -618,7 +893,7 @@ class ExternalFilterComponent {
|
|
|
618
893
|
});
|
|
619
894
|
};
|
|
620
895
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ExternalFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
621
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ExternalFilterComponent, isStandalone: true, selector: "external-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _items = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _items.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n [collapsible]=\"_filter?.collapsible ?? _filter?.collapsable ?? true\">\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _items; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _items; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: SdSection, selector: "sd-section", inputs: ["title", "subTitle", "icon", "iconColor", "collapsed", "collapsible", "collapsable", "hideHeader", "noPaddingBody"], outputs: ["collapsedChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdCheckbox, selector: "sd-checkbox", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "inlineError", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
896
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: ExternalFilterComponent, isStandalone: true, selector: "external-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _filterItems = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _filterItems.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n [collapsible]=\"_filter?.collapsible ?? _filter?.collapsable ?? true\">\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _filterItems; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _filterItems; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: SdSection, selector: "sd-section", inputs: ["title", "subTitle", "icon", "iconColor", "collapsed", "collapsible", "collapsable", "hideHeader", "noPaddingBody"], outputs: ["collapsedChange"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdCheckbox, selector: "sd-checkbox", inputs: ["autoId", "name", "form", "label", "color", "disabled", "viewed", "inlineError", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
622
897
|
}
|
|
623
898
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: ExternalFilterComponent, decorators: [{
|
|
624
899
|
type: Component,
|
|
@@ -637,7 +912,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
637
912
|
FilterValuesPipe,
|
|
638
913
|
SdCheckbox,
|
|
639
914
|
TranslatePipe,
|
|
640
|
-
], template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _items = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _items.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n [collapsible]=\"_filter?.collapsible ?? _filter?.collapsable ?? true\">\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _items; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _items; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"] }]
|
|
915
|
+
], template: "@let _filter = filter();\n@let _autoId = autoId();\n@let _filterItems = filterItems();\n@let _externalFilter = externalFilter();\n@let _inlineExternal = inlineExternal();\n@let _filtered = filtered();\n@let _col = col();\n\n@if (!_filter?.disabled) {\n @if (!isMobileOrTablet && _filterItems.length) {\n <sd-section\n [hideHeader]=\"_filter?.hideExternalFilterToolbar\"\n icon=\"filter_alt\"\n iconColor=\"secondary\"\n [title]=\"'core.component.table.filter' | translate\"\n [collapsible]=\"_filter?.collapsible ?? _filter?.collapsable ?? true\">\n <div class=\"d-flex mr-4\" sdHeaderRight>\n <sd-button\n [autoId]=\"_autoId + 'clear'\"\n [disabled]=\"!_filtered\"\n type=\"link\"\n prefixIcon=\"cleaning_services\"\n [tooltip]=\"'core.component.table.clear-selection' | translate\"\n (click)=\"$event.stopPropagation(); clearFilter($event)\"></sd-button>\n <sd-button\n [autoId]=\"_autoId + 'setting'\"\n type=\"link\"\n prefixIcon=\"settings\"\n [tooltip]=\"'core.component.table.customize' | translate\"\n [matMenuTriggerFor]=\"menu\"\n (click)=\"$event.stopPropagation()\"></sd-button>\n <mat-menu #menu=\"matMenu\" class=\"sd-custom-panel-filter-configuration\" [attr.data-autoid]=\"_autoId + 'setting-menu'\">\n @for (externalFilter of _filterItems; track externalFilter.field) {\n <button\n [attr.data-autoid]=\"_autoId + 'setting-' + externalFilter.field\"\n mat-menu-item\n (click)=\"onCheckboxChange($event, externalFilter)\"\n [disabled]=\"externalFilter.required\">\n <sd-checkbox\n [autoId]=\"_autoId + 'setting-' + externalFilter.field + '-checkbox'\"\n [label]=\"externalFilter.title\"\n [model]=\"_inlineExternal[externalFilter.field]\"\n [disabled]=\"externalFilter.required\" />\n </button>\n }\n </mat-menu>\n </div>\n <div class=\"row mx-0\" style=\"row-gap: 16px\">\n @for (item of _filterItems; track item.field) {\n @if (_inlineExternal[item.field]) {\n <div class=\"col-md-3 col-sm-6 px-8\" [class.col-lg-2]=\"_col === 2\" [class.col-lg-3]=\"_col === 3\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (keyupEnter)=\"onKeyupEnter()\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n [form]=\"form\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'AUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.option.selection === 'MULTIPLEAUTOCOMPLETE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'lazy-values') {\n @if (item.option.selection === 'MULTIPLE') {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n multiple\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else {\n <sd-select\n [autoId]=\"_autoId + item.field\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_externalFilter[item.field]\"\n (sdChange)=\"onFilter(item)\"\n appearance=\"outline\"\n [form]=\"form\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n }\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { form: form, externalFilter: _externalFilter, autoId: _autoId + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n }\n </div>\n @if (_filter?.manualFilter) {\n <div class=\"d-flex justify-content-end mt-16 px-8\">\n <sd-button\n [autoId]=\"_autoId + 'submit'\"\n [disabled]=\"form.invalid\"\n type=\"fill\"\n color=\"primary\"\n [title]=\"'core.component.table.search' | translate\"\n prefixIcon=\"filter_alt\"\n (click)=\"onSubmit()\">\n </sd-button>\n </div>\n }\n </sd-section>\n }\n}\n", styles: [":host{display:block;padding-left:0;padding-right:0}::ng-deep .sd-custom-panel-filter-configuration{width:240px;max-height:550px;overflow-y:auto}\n"] }]
|
|
641
916
|
}], ctorParameters: () => [], propDecorators: { autoIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoId", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], externalFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "externalFilters", required: false }] }], filterRegister: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterRegister", required: false }] }] } });
|
|
642
917
|
|
|
643
918
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
@@ -714,7 +989,7 @@ class MobileFilterComponent {
|
|
|
714
989
|
this.drawer().close();
|
|
715
990
|
};
|
|
716
991
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: MobileFilterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
717
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: MobileFilterComponent, isStandalone: true, selector: "mobile-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, filterDefs: { classPropertyName: "filterDefs", publicName: "filterDefs", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "drawer", first: true, predicate: SdSideDrawer, descendants: true, isSignal: true }], ngImport: i0, template: "@let _autoId = autoId();\n@let _externalFilters = externalFilterItems();\n@let _columns = columnItems();\n@let _filterDefs = filterDefItems();\n@let _workingColumnFilter = workingColumnFilter();\n@let _workingColumnOperator = workingColumnOperator();\n@let _workingExternalFilter = workingExternalFilter();\n@let _cacheValues = cacheValues();\n\n<sd-side-drawer\n #drawer\n [title]=\"'core.component.table.filter' | translate\"\n width=\"90vw\">\n <div class=\"mobile-filter-body\">\n <!-- ============================ -->\n <!-- 1. External filters (inline) -->\n <!-- ============================ -->\n @if (_externalFilters.length) {\n <section class=\"mobile-filter-section\">\n @for (item of _externalFilters; track item.field) {\n <div class=\"mobile-filter-row\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE' || item.option.selection === 'MULTIPLEAUTOCOMPLETE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'lazy-values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { externalFilter: _workingExternalFilter, autoId: _autoId + 'ext-' + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 2. Custom filterDef templates -->\n <!-- ============================ -->\n @if (_filterDefs.length) {\n <section class=\"mobile-filter-section\">\n @for (def of _filterDefs; track def.sdTableFilterDef()) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'def-' + def.sdTableFilterDef()\">\n <ng-container\n *ngTemplateOutlet=\"def.templateRef!; context: { externalFilter: _workingExternalFilter }\">\n </ng-container>\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 3. Column filters -->\n <!-- ============================ -->\n @if (_columns.length) {\n <section class=\"mobile-filter-section\">\n @for (column of _columns; track column.field) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'col-' + column.field\">\n <column-filter\n [autoId]=\"_autoId + 'col'\"\n [column]=\"column\"\n [columnFilter]=\"_workingColumnFilter\"\n [operator]=\"$any(_workingColumnOperator[column.field])\"\n (operatorChange)=\"_workingColumnOperator[column.field] = $event!\"\n [cacheValues]=\"_cacheValues\"\n isMobile>\n </column-filter>\n </div>\n }\n </section>\n }\n </div>\n\n <ng-container sdFooter>\n <div class=\"mobile-filter-footer\">\n <sd-button\n [autoId]=\"_autoId + 'cancel'\"\n class=\"mobile-filter-action\"\n (click)=\"onCancel()\"\n [title]=\"'core.confirm.no' | translate\"\n type=\"link\"\n color=\"secondary\">\n </sd-button>\n <sd-button\n [autoId]=\"_autoId + 'apply'\"\n class=\"mobile-filter-action\"\n (click)=\"onApply()\"\n [title]=\"'core.confirm.yes' | translate\"\n type=\"fill\"\n color=\"primary\">\n </sd-button>\n </div>\n </ng-container>\n</sd-side-drawer>\n", styles: [".mobile-filter-body{display:flex;flex-direction:column;gap:16px;padding:8px 0}.mobile-filter-section{display:flex;flex-direction:column;gap:12px}.mobile-filter-row{display:flex;flex-direction:column}.mobile-filter-footer{display:flex;gap:8px;width:100%}.mobile-filter-action{flex:1 1 50%}.mobile-filter-action ::ng-deep button{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SdSideDrawer, selector: "sd-side-drawer", inputs: ["title", "width", "hideClose", "disableBackdropClose", "drawerClass", "autoId"], outputs: ["sdClosed"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["autoId", "column", "columnFilter", "cacheValues", "value", "operator", "isMobile"], outputs: ["operatorChange", "filterChange", "filterCommit"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
992
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: MobileFilterComponent, isStandalone: true, selector: "mobile-filter", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, externalFilters: { classPropertyName: "externalFilters", publicName: "externalFilters", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, filterDefs: { classPropertyName: "filterDefs", publicName: "filterDefs", isSignal: true, isRequired: false, transformFunction: null }, filterRegister: { classPropertyName: "filterRegister", publicName: "filterRegister", isSignal: true, isRequired: false, transformFunction: null }, cacheValues: { classPropertyName: "cacheValues", publicName: "cacheValues", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "drawer", first: true, predicate: SdSideDrawer, descendants: true, isSignal: true }], ngImport: i0, template: "@let _autoId = autoId();\n@let _externalFilterItems = externalFilterItems();\n@let _columnItems = columnItems();\n@let _filterDefItems = filterDefItems();\n@let _workingColumnFilter = workingColumnFilter();\n@let _workingColumnOperator = workingColumnOperator();\n@let _workingExternalFilter = workingExternalFilter();\n@let _cacheValues = cacheValues();\n\n<sd-side-drawer\n #drawer\n [title]=\"'core.component.table.filter' | translate\"\n width=\"90vw\">\n <div class=\"mobile-filter-body\">\n <!-- ============================ -->\n <!-- 1. External filters (inline) -->\n <!-- ============================ -->\n @if (_externalFilterItems.length) {\n <section class=\"mobile-filter-section\">\n @for (item of _externalFilterItems; track item.field) {\n <div class=\"mobile-filter-row\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE' || item.option.selection === 'MULTIPLEAUTOCOMPLETE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'lazy-values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { externalFilter: _workingExternalFilter, autoId: _autoId + 'ext-' + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 2. Custom filterDef templates -->\n <!-- ============================ -->\n @if (_filterDefItems.length) {\n <section class=\"mobile-filter-section\">\n @for (def of _filterDefItems; track def.sdTableFilterDef()) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'def-' + def.sdTableFilterDef()\">\n <ng-container\n *ngTemplateOutlet=\"def.templateRef!; context: { externalFilter: _workingExternalFilter }\">\n </ng-container>\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 3. Column filters -->\n <!-- ============================ -->\n @if (_columnItems.length) {\n <section class=\"mobile-filter-section\">\n @for (column of _columnItems; track column.field) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'col-' + column.field\">\n <column-filter\n [autoId]=\"_autoId + 'col'\"\n [column]=\"column\"\n [columnFilter]=\"_workingColumnFilter\"\n [operator]=\"$any(_workingColumnOperator[column.field])\"\n (operatorChange)=\"_workingColumnOperator[column.field] = $event!\"\n [cacheValues]=\"_cacheValues\"\n isMobile>\n </column-filter>\n </div>\n }\n </section>\n }\n </div>\n\n <ng-container sdFooter>\n <div class=\"mobile-filter-footer\">\n <sd-button\n [autoId]=\"_autoId + 'cancel'\"\n class=\"mobile-filter-action\"\n (click)=\"onCancel()\"\n [title]=\"'core.confirm.no' | translate\"\n type=\"link\"\n color=\"secondary\">\n </sd-button>\n <sd-button\n [autoId]=\"_autoId + 'apply'\"\n class=\"mobile-filter-action\"\n (click)=\"onApply()\"\n [title]=\"'core.confirm.yes' | translate\"\n type=\"fill\"\n color=\"primary\">\n </sd-button>\n </div>\n </ng-container>\n</sd-side-drawer>\n", styles: [".mobile-filter-body{display:flex;flex-direction:column;gap:16px;padding:8px 0}.mobile-filter-section{display:flex;flex-direction:column;gap:12px}.mobile-filter-row{display:flex;flex-direction:column}.mobile-filter-footer{display:flex;gap:8px;width:100%}.mobile-filter-action{flex:1 1 50%}.mobile-filter-action ::ng-deep button{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SdSideDrawer, selector: "sd-side-drawer", inputs: ["title", "width", "hideClose", "disableBackdropClose", "drawerClass", "autoId"], outputs: ["sdClosed"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: ColumnFilterComponent, selector: "column-filter", inputs: ["autoId", "column", "columnFilter", "cacheValues", "value", "operator", "isMobile"], outputs: ["operatorChange", "filterChange", "filterCommit"] }, { kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdInputNumber, selector: "sd-input-number", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "type", "precision", "format", "min", "max", "validator", "inlineError", "hyperlink", "appearance", "floatLabel", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "component", type: SdSelect, selector: "sd-select", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "valueField", "displayField", "disabledField", "cacheChecksum", "limit", "hyperlink", "minWidthPanel", "hideInlineError", "required", "disabled", "viewed", "multiple", "clearable", "validator", "inlineError", "appearance", "floatLabel", "items", "model"], outputs: ["modelChange", "sdChange", "sdSelection"] }, { kind: "component", type: SdDate, selector: "sd-date", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDatetime, selector: "sd-datetime", inputs: ["autoId", "name", "size", "form", "label", "helperText", "placeholder", "hideInlineError", "required", "disabled", "viewed", "showSeconds", "clearable", "inlineError", "hyperlink", "appearance", "floatLabel", "min", "minDate", "max", "maxDate", "model"], outputs: ["modelChange", "sdChange", "sdFocus"] }, { kind: "component", type: SdDateRange$1, selector: "sd-date-range", inputs: ["autoId", "name", "size", "form", "label", "helperText", "hideInlineError", "required", "disabled", "viewed", "clearable", "appearance", "floatLabel", "min", "max", "model"], outputs: ["modelChange", "sdChange"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: FilterValuesPipe, name: "filterValues" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
718
993
|
}
|
|
719
994
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: MobileFilterComponent, decorators: [{
|
|
720
995
|
type: Component,
|
|
@@ -731,7 +1006,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
731
1006
|
SdDateRange$1,
|
|
732
1007
|
FilterValuesPipe,
|
|
733
1008
|
TranslatePipe,
|
|
734
|
-
], template: "@let _autoId = autoId();\n@let
|
|
1009
|
+
], template: "@let _autoId = autoId();\n@let _externalFilterItems = externalFilterItems();\n@let _columnItems = columnItems();\n@let _filterDefItems = filterDefItems();\n@let _workingColumnFilter = workingColumnFilter();\n@let _workingColumnOperator = workingColumnOperator();\n@let _workingExternalFilter = workingExternalFilter();\n@let _cacheValues = cacheValues();\n\n<sd-side-drawer\n #drawer\n [title]=\"'core.component.table.filter' | translate\"\n width=\"90vw\">\n <div class=\"mobile-filter-body\">\n <!-- ============================ -->\n <!-- 1. External filters (inline) -->\n <!-- ============================ -->\n @if (_externalFilterItems.length) {\n <section class=\"mobile-filter-section\">\n @for (item of _externalFilterItems; track item.field) {\n <div class=\"mobile-filter-row\">\n @if (item.type === 'string') {\n <sd-input\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n type=\"text\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input>\n } @else if (item.type === 'number') {\n <sd-input-number\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-input-number>\n } @else if (item.type === 'boolean') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"[\n { value: true, display: item.option?.displayOnTrue || 'True' },\n { value: false, display: item.option?.displayOnFalse || 'False' },\n ]\"\n valueField=\"value\"\n displayField=\"display\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'date') {\n <sd-date\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-date>\n } @else if (item.type === 'datetime') {\n <sd-datetime\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n hideInlineError>\n </sd-datetime>\n } @else if (item.type === 'daterange') {\n <sd-date-range\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n [required]=\"item.required\"\n [min]=\"item.minDate\"\n [max]=\"item.maxDate\"\n appearance=\"outline\"\n hideInlineError>\n </sd-date-range>\n } @else if (item.type === 'values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items | filterValues | async\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE' || item.option.selection === 'MULTIPLEAUTOCOMPLETE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'lazy-values') {\n <sd-select\n [autoId]=\"_autoId + 'ext-' + item.field\"\n size=\"sm\"\n [label]=\"item.title\"\n [items]=\"item.option.items\"\n [valueField]=\"item.option.valueField\"\n [displayField]=\"item.option.displayField\"\n [(model)]=\"_workingExternalFilter[item.field]\"\n appearance=\"outline\"\n [multiple]=\"item.option.selection === 'MULTIPLE'\"\n [required]=\"item.required\"\n hideInlineError>\n </sd-select>\n } @else if (item.type === 'custom' && item.filterDef) {\n <ng-container\n *ngTemplateOutlet=\"\n item.filterDef;\n context: { externalFilter: _workingExternalFilter, autoId: _autoId + 'ext-' + item.field }\n \">\n </ng-container>\n }\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 2. Custom filterDef templates -->\n <!-- ============================ -->\n @if (_filterDefItems.length) {\n <section class=\"mobile-filter-section\">\n @for (def of _filterDefItems; track def.sdTableFilterDef()) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'def-' + def.sdTableFilterDef()\">\n <ng-container\n *ngTemplateOutlet=\"def.templateRef!; context: { externalFilter: _workingExternalFilter }\">\n </ng-container>\n </div>\n }\n </section>\n }\n\n <!-- ============================ -->\n <!-- 3. Column filters -->\n <!-- ============================ -->\n @if (_columnItems.length) {\n <section class=\"mobile-filter-section\">\n @for (column of _columnItems; track column.field) {\n <div class=\"mobile-filter-row\" [attr.data-autoid]=\"_autoId + 'col-' + column.field\">\n <column-filter\n [autoId]=\"_autoId + 'col'\"\n [column]=\"column\"\n [columnFilter]=\"_workingColumnFilter\"\n [operator]=\"$any(_workingColumnOperator[column.field])\"\n (operatorChange)=\"_workingColumnOperator[column.field] = $event!\"\n [cacheValues]=\"_cacheValues\"\n isMobile>\n </column-filter>\n </div>\n }\n </section>\n }\n </div>\n\n <ng-container sdFooter>\n <div class=\"mobile-filter-footer\">\n <sd-button\n [autoId]=\"_autoId + 'cancel'\"\n class=\"mobile-filter-action\"\n (click)=\"onCancel()\"\n [title]=\"'core.confirm.no' | translate\"\n type=\"link\"\n color=\"secondary\">\n </sd-button>\n <sd-button\n [autoId]=\"_autoId + 'apply'\"\n class=\"mobile-filter-action\"\n (click)=\"onApply()\"\n [title]=\"'core.confirm.yes' | translate\"\n type=\"fill\"\n color=\"primary\">\n </sd-button>\n </div>\n </ng-container>\n</sd-side-drawer>\n", styles: [".mobile-filter-body{display:flex;flex-direction:column;gap:16px;padding:8px 0}.mobile-filter-section{display:flex;flex-direction:column;gap:12px}.mobile-filter-row{display:flex;flex-direction:column}.mobile-filter-footer{display:flex;gap:8px;width:100%}.mobile-filter-action{flex:1 1 50%}.mobile-filter-action ::ng-deep button{width:100%}\n"] }]
|
|
735
1010
|
}], propDecorators: { autoIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoId", required: false }] }], filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: false }] }], externalFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "externalFilters", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], filterDefs: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterDefs", required: false }] }], filterRegister: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterRegister", required: false }] }], cacheValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "cacheValues", required: false }] }], drawer: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SdSideDrawer), { isSignal: true }] }] } });
|
|
736
1011
|
|
|
737
1012
|
class ActionFilterPipe {
|
|
@@ -842,11 +1117,11 @@ class SelectorActionComponent {
|
|
|
842
1117
|
}
|
|
843
1118
|
};
|
|
844
1119
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SelectorActionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
845
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SelectorActionComponent, isStandalone: true, selector: "selector-action", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, tableOption: { classPropertyName: "tableOption", publicName: "tableOption", isSignal: true, isRequired: false, transformFunction: null }, selectedTableItems: { classPropertyName: "selectedTableItems", publicName: "selectedTableItems", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clear: "clear" }, ngImport: i0, template: "@let _actions = selectedTableItems() | actionFilter: tableOption()?.selector?.actions;\n@let
|
|
1120
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SelectorActionComponent, isStandalone: true, selector: "selector-action", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, tableOption: { classPropertyName: "tableOption", publicName: "tableOption", isSignal: true, isRequired: false, transformFunction: null }, selectedTableItems: { classPropertyName: "selectedTableItems", publicName: "selectedTableItems", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clear: "clear" }, ngImport: i0, template: "@let _actions = selectedTableItems() | actionFilter: tableOption()?.selector?.actions;\n@let _selectedTableItems = selectedTableItems();\n@let _autoId = autoId();\n\n<sd-quick-action [opened]=\"opened()\">\n <div class=\"d-flex align-items-center\" sdMessage>\n <div class=\"c-bg-length\">\n <span class=\"c-length\">{{ _selectedTableItems?.length }}</span>\n </div>\n <div class=\"c-message\">\n {{ message() }}\n </div>\n </div>\n\n <div class=\"d-flex align-items-center mr-8\" sdAction>\n @for (action of _actions; track $index) {\n @if (action.variant === 'normal') {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + $index : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon\"\n [color]=\"action.color\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet\"\n [title]=\"action.title\"\n (click)=\"onClickAction(action)\"></sd-button>\n } @else if (action.variant === 'children') {\n @let _actionIndex = $index;\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + _actionIndex : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon || 'more_vert'\"\n [color]=\"action.color || 'secondary'\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet || 'material-icons-outlined'\"\n [title]=\"action.title\"\n [matMenuTriggerFor]=\"menu\">\n </sd-button>\n <mat-menu #menu=\"matMenu\">\n <span>\n @for (child of action.children; track $index) {\n <button\n mat-menu-item\n [attr.data-autoid]=\"_autoId ? _autoId + '-action-' + _actionIndex + '-' + $index : null\"\n (click)=\"onClickAction(child)\">\n @if (child.icon) {\n <mat-icon [fontSet]=\"child.fontSet || 'material-icons-outlined'\" class=\"c-icon\">{{ child.icon }}</mat-icon>\n }\n <span> {{ child.title }}</span>\n </button>\n }\n </span>\n </mat-menu>\n }\n }\n <!-- N\u00FAt close lu\u00F4n hi\u1EC7n k\u1EC3 c\u1EA3 kh\u00F4ng c\u00F3 action \u2014 \u0111\u1EA3m b\u1EA3o user c\u00F3 l\u1ED1i tho\u00E1t clear selection -->\n <sd-button [autoId]=\"_autoId ? _autoId + '-clear-selection' : null\" class=\"ml-4\" prefixIcon=\"close\" color=\"secondary\" type=\"outline\" (click)=\"onClear()\" width=\"35px\"></sd-button>\n </div>\n</sd-quick-action>\n", styles: [".c-bg-length{display:flex;flex-direction:column;align-items:flex-start;padding:12px 8px;position:static;width:auto;min-width:48px;height:48px;left:0;top:0;background:var(--sd-primary);border-radius:4px 0 0 4px}.c-bg-length .c-length{position:static;width:auto;min-width:32px;height:24px;left:8px;top:12px;font-family:Roboto;font-style:normal;font-weight:500;font-size:16px;line-height:24px;text-align:center;color:#fff}.c-message{position:static;min-width:200px;height:20px;left:0;top:6px;font-family:Roboto;font-style:normal;font-weight:400;font-size:14px;line-height:20px;color:#000;margin:0 0 0 8px}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdQuickAction, selector: "sd-quick-action", inputs: ["opened"] }, { kind: "pipe", type: ActionFilterPipe, name: "actionFilter" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
846
1121
|
}
|
|
847
1122
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SelectorActionComponent, decorators: [{
|
|
848
1123
|
type: Component,
|
|
849
|
-
args: [{ selector: 'selector-action', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatIconModule, MatMenuModule, SdButton, SdQuickAction, ActionFilterPipe], template: "@let _actions = selectedTableItems() | actionFilter: tableOption()?.selector?.actions;\n@let
|
|
1124
|
+
args: [{ selector: 'selector-action', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatIconModule, MatMenuModule, SdButton, SdQuickAction, ActionFilterPipe], template: "@let _actions = selectedTableItems() | actionFilter: tableOption()?.selector?.actions;\n@let _selectedTableItems = selectedTableItems();\n@let _autoId = autoId();\n\n<sd-quick-action [opened]=\"opened()\">\n <div class=\"d-flex align-items-center\" sdMessage>\n <div class=\"c-bg-length\">\n <span class=\"c-length\">{{ _selectedTableItems?.length }}</span>\n </div>\n <div class=\"c-message\">\n {{ message() }}\n </div>\n </div>\n\n <div class=\"d-flex align-items-center mr-8\" sdAction>\n @for (action of _actions; track $index) {\n @if (action.variant === 'normal') {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + $index : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon\"\n [color]=\"action.color\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet\"\n [title]=\"action.title\"\n (click)=\"onClickAction(action)\"></sd-button>\n } @else if (action.variant === 'children') {\n @let _actionIndex = $index;\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-action-' + _actionIndex : null\"\n class=\"ml-4\"\n [tooltip]=\"action.tooltip\"\n [prefixIcon]=\"action.icon || 'more_vert'\"\n [color]=\"action.color || 'secondary'\"\n [type]=\"action.type || 'light'\"\n [fontSet]=\"action.fontSet || 'material-icons-outlined'\"\n [title]=\"action.title\"\n [matMenuTriggerFor]=\"menu\">\n </sd-button>\n <mat-menu #menu=\"matMenu\">\n <span>\n @for (child of action.children; track $index) {\n <button\n mat-menu-item\n [attr.data-autoid]=\"_autoId ? _autoId + '-action-' + _actionIndex + '-' + $index : null\"\n (click)=\"onClickAction(child)\">\n @if (child.icon) {\n <mat-icon [fontSet]=\"child.fontSet || 'material-icons-outlined'\" class=\"c-icon\">{{ child.icon }}</mat-icon>\n }\n <span> {{ child.title }}</span>\n </button>\n }\n </span>\n </mat-menu>\n }\n }\n <!-- N\u00FAt close lu\u00F4n hi\u1EC7n k\u1EC3 c\u1EA3 kh\u00F4ng c\u00F3 action \u2014 \u0111\u1EA3m b\u1EA3o user c\u00F3 l\u1ED1i tho\u00E1t clear selection -->\n <sd-button [autoId]=\"_autoId ? _autoId + '-clear-selection' : null\" class=\"ml-4\" prefixIcon=\"close\" color=\"secondary\" type=\"outline\" (click)=\"onClear()\" width=\"35px\"></sd-button>\n </div>\n</sd-quick-action>\n", styles: [".c-bg-length{display:flex;flex-direction:column;align-items:flex-start;padding:12px 8px;position:static;width:auto;min-width:48px;height:48px;left:0;top:0;background:var(--sd-primary);border-radius:4px 0 0 4px}.c-bg-length .c-length{position:static;width:auto;min-width:32px;height:24px;left:8px;top:12px;font-family:Roboto;font-style:normal;font-weight:500;font-size:16px;line-height:24px;text-align:center;color:#fff}.c-message{position:static;min-width:200px;height:20px;left:0;top:6px;font-family:Roboto;font-style:normal;font-weight:400;font-size:14px;line-height:20px;color:#000;margin:0 0 0 8px}\n"] }]
|
|
850
1125
|
}], propDecorators: { autoIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoId", required: false }] }], tableOption: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableOption", required: false }] }], selectedTableItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedTableItems", required: false }] }], clear: [{ type: i0.Output, args: ["clear"] }] } });
|
|
851
1126
|
|
|
852
1127
|
const DEFAULT_TABLE_CONFIG = {
|
|
@@ -2411,13 +2686,13 @@ class TableExportService {
|
|
|
2411
2686
|
}
|
|
2412
2687
|
}
|
|
2413
2688
|
else if (column.type === 'date') {
|
|
2414
|
-
obj[fieldStr] = DateUtilities.toFormat(itemValue, 'yyyy/MM/dd');
|
|
2689
|
+
obj[fieldStr] = DateUtilities$1.toFormat(itemValue, 'yyyy/MM/dd');
|
|
2415
2690
|
}
|
|
2416
2691
|
else if (column.type === 'datetime') {
|
|
2417
|
-
obj[fieldStr] = DateUtilities.toFormat(itemValue, 'yyyy/MM/dd HH:mm:ss');
|
|
2692
|
+
obj[fieldStr] = DateUtilities$1.toFormat(itemValue, 'yyyy/MM/dd HH:mm:ss');
|
|
2418
2693
|
}
|
|
2419
2694
|
else if (column.type === 'time') {
|
|
2420
|
-
obj[fieldStr] = DateUtilities.toFormat(itemValue, 'HH:mm:ss');
|
|
2695
|
+
obj[fieldStr] = DateUtilities$1.toFormat(itemValue, 'HH:mm:ss');
|
|
2421
2696
|
}
|
|
2422
2697
|
else if (column.type === 'values' || column.type === 'lazy-values') {
|
|
2423
2698
|
const vals = (Array.isArray(itemValue) ? itemValue : [itemValue]).filter(e => !!e?.toString());
|
|
@@ -2712,8 +2987,8 @@ class TableFormatService {
|
|
|
2712
2987
|
// PRIVATE HELPERS
|
|
2713
2988
|
// ==========================================
|
|
2714
2989
|
#formatDateDisplay(value, type) {
|
|
2715
|
-
const date = DateUtilities.toFormat(value, 'dd/MM/yyyy');
|
|
2716
|
-
const time = DateUtilities.toFormat(value, 'HH:mm:ss');
|
|
2990
|
+
const date = DateUtilities$1.toFormat(value, 'dd/MM/yyyy');
|
|
2991
|
+
const time = DateUtilities$1.toFormat(value, 'HH:mm:ss');
|
|
2717
2992
|
if (type === 'datetime') {
|
|
2718
2993
|
return time && date ? `<div class="T14R">${date}<span class="T14R text-black400 ml-4">${time}</span></div>` : '';
|
|
2719
2994
|
}
|
|
@@ -2774,44 +3049,305 @@ const buildColumnWidthMap = (column) => {
|
|
|
2774
3049
|
return result;
|
|
2775
3050
|
};
|
|
2776
3051
|
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
const
|
|
2794
|
-
if (
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
}
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
3052
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3053
|
+
const isTableItem = (item) => !!item && typeof item === 'object' && 'data' in item && 'meta' in item;
|
|
3054
|
+
const resolveItemData = (item) => (isTableItem(item) ? item.data : item);
|
|
3055
|
+
const hasActiveColumnFilter = (rawColumnFilter = {}, columns = []) => columns.some(col => {
|
|
3056
|
+
const v = rawColumnFilter[col.field];
|
|
3057
|
+
if (Array.isArray(v))
|
|
3058
|
+
return v.length > 0;
|
|
3059
|
+
if (v && typeof v === 'object')
|
|
3060
|
+
return !!v.from || !!v.to;
|
|
3061
|
+
return v !== undefined && v !== null && v !== '';
|
|
3062
|
+
});
|
|
3063
|
+
const matchesColumnFilter = (data, columns = [], rawColumnFilter = {}) => {
|
|
3064
|
+
for (const column of columns) {
|
|
3065
|
+
const { field, type } = column;
|
|
3066
|
+
const filterValue = (rawColumnFilter[field] || '').toString().trim().toLowerCase();
|
|
3067
|
+
const rawColVal = Utilities.getNestedValue(data, field);
|
|
3068
|
+
const columnValue = (rawColVal || '').toString().trim().toLowerCase();
|
|
3069
|
+
if (filterValue) {
|
|
3070
|
+
if (!columnValue && type !== 'datetime' && type !== 'date' && type !== 'time') {
|
|
3071
|
+
return false;
|
|
3072
|
+
}
|
|
3073
|
+
if (type === 'string') {
|
|
3074
|
+
if (columnValue.indexOf(filterValue) === -1) {
|
|
3075
|
+
return false;
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
else if (type === 'values' || type === 'lazy-values') {
|
|
3079
|
+
const columnType = column;
|
|
3080
|
+
const isMultiple = columnType.option.selection === 'MULTIPLE';
|
|
3081
|
+
if (isMultiple && Array.isArray(rawColVal)) {
|
|
3082
|
+
const columnValues = rawColVal.map((i) => (Utilities.getNestedValue(i, columnType.option.valueField) ?? '').toString().trim().toLowerCase()) ??
|
|
3083
|
+
[];
|
|
3084
|
+
const filterValues = rawColumnFilter[field]?.map((v) => (v ?? '').toString().trim().toLowerCase());
|
|
3085
|
+
if (filterValues?.length && filterValues.every(fv => !columnValues.includes(fv))) {
|
|
3086
|
+
return false;
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
else {
|
|
3090
|
+
if (columnValue !== filterValue) {
|
|
3091
|
+
return false;
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
else if (type === 'number') {
|
|
3096
|
+
const fValue = +filterValue.replace('>=', '').replace('<=', '').replace('>', '').replace('<', '');
|
|
3097
|
+
const cValue = +columnValue;
|
|
3098
|
+
if (fValue || fValue === 0) {
|
|
3099
|
+
if (!cValue && cValue !== 0) {
|
|
3100
|
+
return false;
|
|
3101
|
+
}
|
|
3102
|
+
if (filterValue.indexOf('>=') > -1 && cValue < fValue) {
|
|
3103
|
+
return false;
|
|
3104
|
+
}
|
|
3105
|
+
else if (filterValue.indexOf('<=') > -1 && cValue > fValue) {
|
|
3106
|
+
return false;
|
|
3107
|
+
}
|
|
3108
|
+
else if (filterValue.indexOf('<') > -1 && cValue >= fValue) {
|
|
3109
|
+
return false;
|
|
3110
|
+
}
|
|
3111
|
+
else if (filterValue.indexOf('>') > -1 && cValue <= fValue) {
|
|
3112
|
+
return false;
|
|
3113
|
+
}
|
|
3114
|
+
else if (cValue !== fValue) {
|
|
3115
|
+
return false;
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
else if (type === 'boolean') {
|
|
3120
|
+
if ((filterValue === '1' || filterValue === 'true') && columnValue !== '1' && columnValue !== 'true') {
|
|
3121
|
+
return false;
|
|
3122
|
+
}
|
|
3123
|
+
else if ((filterValue === '0' || filterValue === 'false') && columnValue !== '0' && columnValue !== 'false') {
|
|
3124
|
+
return false;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
else if (type === 'datetime' || type === 'date' || type === 'time') {
|
|
3128
|
+
const from = rawColumnFilter[field]?.from ?? rawColumnFilter[field];
|
|
3129
|
+
const to = rawColumnFilter[field]?.to ?? rawColumnFilter[field];
|
|
3130
|
+
const fromDate = DateUtilities$1.begin(from);
|
|
3131
|
+
const toDate = DateUtilities$1.end(to);
|
|
3132
|
+
if (fromDate || toDate) {
|
|
3133
|
+
if (!columnValue) {
|
|
3134
|
+
return false;
|
|
3135
|
+
}
|
|
3136
|
+
const columnTime = new Date(columnValue).getTime();
|
|
3137
|
+
const fromDateTime = fromDate?.getTime() || null;
|
|
3138
|
+
const toDateTime = toDate?.getTime() || null;
|
|
3139
|
+
if (fromDateTime && fromDateTime > columnTime) {
|
|
3140
|
+
return false;
|
|
3141
|
+
}
|
|
3142
|
+
if (toDateTime && columnTime > toDateTime) {
|
|
3143
|
+
return false;
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
return true;
|
|
3150
|
+
};
|
|
3151
|
+
const filterLocalItems = (localItems, option, filterInfo) => {
|
|
3152
|
+
const { columns } = option;
|
|
3153
|
+
const { rawColumnFilter, orderBy, orderDirection, pageSize, pageNumber } = filterInfo;
|
|
3154
|
+
const matchesData = (data) => matchesColumnFilter(data, columns, rawColumnFilter);
|
|
3155
|
+
const treeOpt = option.tree;
|
|
3156
|
+
const treeSearch = option.type === 'local' && treeOpt?.loadType === 'static' && hasActiveColumnFilter(rawColumnFilter, columns);
|
|
3157
|
+
const treeSearchPredicate = treeSearch ? matchesData : undefined;
|
|
3158
|
+
const items = treeSearch
|
|
3159
|
+
? localItems.filter(item => subtreeMatches(resolveItemData(item), matchesData, treeOpt))
|
|
3160
|
+
: localItems.filter(item => matchesData(resolveItemData(item)));
|
|
3161
|
+
if (orderBy && orderDirection) {
|
|
3162
|
+
const column = columns.find(e => e.field === orderBy);
|
|
3163
|
+
if (column) {
|
|
3164
|
+
const { type, field } = column;
|
|
3165
|
+
items.sort((tableItemCurrent, tableItemNext) => {
|
|
3166
|
+
const dataVal = Utilities.getNestedValue(resolveItemData(tableItemCurrent), field);
|
|
3167
|
+
const nextVal = Utilities.getNestedValue(resolveItemData(tableItemNext), field);
|
|
3168
|
+
if (type === 'number') {
|
|
3169
|
+
return (dataVal || 0) - (nextVal || 0);
|
|
3170
|
+
}
|
|
3171
|
+
if (type === 'date' || type === 'datetime' || type === 'time') {
|
|
3172
|
+
const d1 = new Date(dataVal || '').getTime();
|
|
3173
|
+
const d2 = new Date(nextVal || '').getTime();
|
|
3174
|
+
return d1 - d2;
|
|
3175
|
+
}
|
|
3176
|
+
const s1 = (dataVal || '').toString();
|
|
3177
|
+
const s2 = (nextVal || '').toString();
|
|
3178
|
+
if (s1 > s2) {
|
|
3179
|
+
return 1;
|
|
3180
|
+
}
|
|
3181
|
+
if (s1 < s2) {
|
|
3182
|
+
return -1;
|
|
3183
|
+
}
|
|
3184
|
+
return 0;
|
|
3185
|
+
});
|
|
3186
|
+
if (orderDirection === 'DESC') {
|
|
3187
|
+
items.reverse();
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
return {
|
|
3192
|
+
items: items.filter((item, index) => index >= pageNumber * pageSize && index < (pageNumber + 1) * pageSize),
|
|
3193
|
+
total: items.length,
|
|
3194
|
+
treeSearchPredicate,
|
|
3195
|
+
};
|
|
3196
|
+
};
|
|
3197
|
+
|
|
3198
|
+
const isGroupHeader = (item) => !!item?.meta?.group?.items?.length;
|
|
3199
|
+
const isChildRow = (item) => (item?.meta.tree?.level ?? 0) > 0;
|
|
3200
|
+
const isRootReorderRow = (item) => !!item && !isGroupHeader(item) && !isChildRow(item);
|
|
3201
|
+
const moveItem = (items, fromIndex, toIndex) => {
|
|
3202
|
+
const next = [...items];
|
|
3203
|
+
const [moved] = next.splice(fromIndex, 1);
|
|
3204
|
+
if (!moved)
|
|
3205
|
+
return next;
|
|
3206
|
+
next.splice(toIndex, 0, moved);
|
|
3207
|
+
return next;
|
|
3208
|
+
};
|
|
3209
|
+
const isReorderDisabled = (item, option, index = -1) => {
|
|
3210
|
+
if (isChildRow(item))
|
|
3211
|
+
return true;
|
|
3212
|
+
if (!option?.disabled || isGroupHeader(item))
|
|
3213
|
+
return false;
|
|
3214
|
+
return option.disabled(item.data, index);
|
|
3215
|
+
};
|
|
3216
|
+
const sameReorderGroup = (a, b, allItems) => {
|
|
3217
|
+
const groupOf = (item) => {
|
|
3218
|
+
let lastGroupIdx = -1;
|
|
3219
|
+
for (let i = 0; i < allItems.length; i++) {
|
|
3220
|
+
if (isGroupHeader(allItems[i]))
|
|
3221
|
+
lastGroupIdx = i;
|
|
3222
|
+
if (allItems[i] === item)
|
|
3223
|
+
return lastGroupIdx;
|
|
3224
|
+
}
|
|
3225
|
+
return -1;
|
|
3226
|
+
};
|
|
3227
|
+
return groupOf(a) === groupOf(b);
|
|
3228
|
+
};
|
|
3229
|
+
const canSortReorder = ({ enabled, index, dragItem, allItems = [], hasGroup }) => {
|
|
3230
|
+
if (!enabled)
|
|
3231
|
+
return false;
|
|
3232
|
+
const targetItem = allItems[index];
|
|
3233
|
+
if (!isRootReorderRow(targetItem))
|
|
3234
|
+
return false;
|
|
3235
|
+
if (isChildRow(dragItem))
|
|
3236
|
+
return false;
|
|
3237
|
+
if (hasGroup) {
|
|
3238
|
+
return sameReorderGroup(dragItem, targetItem, allItems);
|
|
3239
|
+
}
|
|
3240
|
+
return true;
|
|
3241
|
+
};
|
|
3242
|
+
const toReorderItemsIndex = (renderedItems, renderedIndex) => {
|
|
3243
|
+
let count = 0;
|
|
3244
|
+
for (let i = 0; i < renderedIndex; i++) {
|
|
3245
|
+
if (isRootReorderRow(renderedItems[i]))
|
|
3246
|
+
count++;
|
|
3247
|
+
}
|
|
3248
|
+
return count;
|
|
3249
|
+
};
|
|
3250
|
+
const reorderTableItems = ({ items, renderedItems, previousRenderedIndex, currentRenderedIndex, localItems, }) => {
|
|
3251
|
+
const fromIndex = toReorderItemsIndex(renderedItems, previousRenderedIndex);
|
|
3252
|
+
const toIndex = toReorderItemsIndex(renderedItems, currentRenderedIndex);
|
|
3253
|
+
const nextItems = moveItem(items, fromIndex, toIndex);
|
|
3254
|
+
let nextLocalItems = localItems;
|
|
3255
|
+
if (localItems) {
|
|
3256
|
+
const localPositions = items.map(item => localItems.indexOf(item));
|
|
3257
|
+
if (localPositions.every(p => p >= 0)) {
|
|
3258
|
+
nextLocalItems = [...localItems];
|
|
3259
|
+
nextItems.forEach((item, i) => {
|
|
3260
|
+
nextLocalItems[localPositions[i]] = item;
|
|
3261
|
+
});
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
return {
|
|
3265
|
+
items: nextItems,
|
|
3266
|
+
localItems: nextLocalItems,
|
|
3267
|
+
fromIndex,
|
|
3268
|
+
toIndex,
|
|
3269
|
+
};
|
|
3270
|
+
};
|
|
3271
|
+
|
|
3272
|
+
const getSelectionRows = (roots, treeOpt) => treeOpt ? flattenTree(roots, treeOpt) : roots;
|
|
3273
|
+
const getSelectedRowData = (rows) => rows.filter(row => row.meta.selector.isSelected).map(row => row.data);
|
|
3274
|
+
const applyDefaultSelected = (roots, treeOpt, defaultSelected) => {
|
|
3275
|
+
if (!defaultSelected)
|
|
3276
|
+
return;
|
|
3277
|
+
const rows = treeOpt ? collectFormattedTreeRows(roots) : roots;
|
|
3278
|
+
rows.forEach(item => {
|
|
3279
|
+
item.meta.selector.isSelected = defaultSelected(item.data);
|
|
3280
|
+
});
|
|
3281
|
+
};
|
|
3282
|
+
const resolveSelectAllState = (visibleRows) => visibleRows.length > 0 && visibleRows.every(row => row.meta.selector?.isSelected);
|
|
3283
|
+
const restorePreservedSelection = (visibleRows, preservedSelectedMap) => {
|
|
3284
|
+
visibleRows.forEach(item => {
|
|
3285
|
+
if (preservedSelectedMap.has(item.meta.id)) {
|
|
3286
|
+
item.meta.selector.isSelected = true;
|
|
3287
|
+
preservedSelectedMap.set(item.meta.id, item);
|
|
3288
|
+
}
|
|
3289
|
+
});
|
|
3290
|
+
};
|
|
3291
|
+
const syncPreservedSelection = (visibleRows, preservedSelectedMap) => {
|
|
3292
|
+
visibleRows.forEach(item => {
|
|
3293
|
+
const id = item.meta.id;
|
|
3294
|
+
if (item.meta.selector.isSelected) {
|
|
3295
|
+
preservedSelectedMap.set(id, item);
|
|
3296
|
+
}
|
|
3297
|
+
else {
|
|
3298
|
+
preservedSelectedMap.delete(id);
|
|
3299
|
+
}
|
|
3300
|
+
});
|
|
3301
|
+
return Array.from(preservedSelectedMap.values());
|
|
3302
|
+
};
|
|
3303
|
+
|
|
3304
|
+
class SdTableFilterService {
|
|
3305
|
+
storageService;
|
|
3306
|
+
#filterConfiguration = 'GRID-FILTER-CONFIGURATION';
|
|
3307
|
+
#filterValue = 'GRID-FILTER-VALUE';
|
|
3308
|
+
#cache = {};
|
|
3309
|
+
constructor(storageService) {
|
|
3310
|
+
this.storageService = storageService;
|
|
3311
|
+
}
|
|
3312
|
+
#hasOwnValue = (values, field) => {
|
|
3313
|
+
return !!values && Object.prototype.hasOwnProperty.call(values, field);
|
|
3314
|
+
};
|
|
3315
|
+
#resolveKey = (filter, args) => {
|
|
3316
|
+
const { id, columns, externalFilters } = args;
|
|
3317
|
+
const tempKey = Utilities.hash({
|
|
3318
|
+
id,
|
|
3319
|
+
columns: columns?.map(e => e.field).filter(field => !!field) || [],
|
|
3320
|
+
externalFilters: externalFilters?.map(e => e.field).filter(field => !!field) || [],
|
|
3321
|
+
});
|
|
3322
|
+
return {
|
|
3323
|
+
tempKey,
|
|
3324
|
+
key: filter?.key || tempKey,
|
|
3325
|
+
cacheSession: !filter?.key,
|
|
3326
|
+
};
|
|
3327
|
+
};
|
|
3328
|
+
register = (filter, args) => {
|
|
3329
|
+
const { key, tempKey, cacheSession } = this.#resolveKey(filter, args);
|
|
3330
|
+
if (args.force) {
|
|
3331
|
+
delete this.#cache[key];
|
|
3332
|
+
}
|
|
3333
|
+
if (!this.#cache[key]) {
|
|
3334
|
+
// Setting của filter configuration
|
|
3335
|
+
const filterConfiguration = this.storageService.create({
|
|
3336
|
+
prefix: this.#filterConfiguration,
|
|
3337
|
+
key,
|
|
3338
|
+
}, {
|
|
3339
|
+
default: this.#defaultConfiguration(args),
|
|
3340
|
+
type: cacheSession ? 'session' : undefined,
|
|
3341
|
+
});
|
|
3342
|
+
// Lấy giá trị configuration merge với giá trị defaultShowing của args nếu như args có thay đổi
|
|
3343
|
+
filterConfiguration.set(this.#initConfiguration(args, filterConfiguration.get()));
|
|
3344
|
+
// Setting của filter value
|
|
3345
|
+
const filterValue = this.storageService.create({
|
|
3346
|
+
prefix: this.#filterValue,
|
|
3347
|
+
key: !filter?.cacheable ? tempKey : key,
|
|
3348
|
+
}, {
|
|
3349
|
+
default: this.#defaultValue(args),
|
|
3350
|
+
type: cacheSession || !filter?.cacheable ? 'session' : undefined,
|
|
2815
3351
|
});
|
|
2816
3352
|
// Lấy giá trị value merge với giá trị default của args nếu như args có thay đổi
|
|
2817
3353
|
filterValue.set(this.#initValue(args, filterValue.get()));
|
|
@@ -2959,21 +3495,25 @@ class SdTableFilterService {
|
|
|
2959
3495
|
const { columns, externalFilters } = args;
|
|
2960
3496
|
// Filter column
|
|
2961
3497
|
for (const item of columns || []) {
|
|
2962
|
-
|
|
3498
|
+
// why: null is a deliberate cached clear from SD controls; only a missing key should fall back to default.
|
|
3499
|
+
columnFilter[item.field] = this.#hasOwnValue(value?.columnFilter, item.field)
|
|
3500
|
+
? value?.columnFilter?.[item.field]
|
|
3501
|
+
: item?.filter?.default;
|
|
2963
3502
|
if (item?.filter?.operator?.enable && item?.filter?.operator?.default) {
|
|
2964
3503
|
columnOperator[item.field] = item.filter.operator.default;
|
|
2965
3504
|
}
|
|
2966
3505
|
}
|
|
2967
3506
|
// Filter external
|
|
2968
3507
|
for (const item of externalFilters || []) {
|
|
3508
|
+
const hasExternalValue = this.#hasOwnValue(value?.externalFilter, item.field);
|
|
2969
3509
|
if (item.type === 'daterange') {
|
|
2970
3510
|
externalFilter[item.field] = {
|
|
2971
|
-
from: value?.externalFilter?.[item.field]?.from
|
|
2972
|
-
to: value?.externalFilter?.[item.field]?.to
|
|
3511
|
+
from: hasExternalValue ? value?.externalFilter?.[item.field]?.from : item.default?.from,
|
|
3512
|
+
to: hasExternalValue ? value?.externalFilter?.[item.field]?.to : item.default?.to,
|
|
2973
3513
|
};
|
|
2974
3514
|
}
|
|
2975
3515
|
else {
|
|
2976
|
-
externalFilter[item.field] = value?.externalFilter?.[item.field]
|
|
3516
|
+
externalFilter[item.field] = hasExternalValue ? value?.externalFilter?.[item.field] : item?.default;
|
|
2977
3517
|
}
|
|
2978
3518
|
}
|
|
2979
3519
|
return {
|
|
@@ -3083,13 +3623,17 @@ class SdTable {
|
|
|
3083
3623
|
isSelectAll = signal(false, ...(ngDevMode ? [{ debugName: "isSelectAll" }] : []));
|
|
3084
3624
|
isFiltered = signal(false, ...(ngDevMode ? [{ debugName: "isFiltered" }] : []));
|
|
3085
3625
|
requireFiltered = signal(false, ...(ngDevMode ? [{ debugName: "requireFiltered" }] : []));
|
|
3086
|
-
#tableId =
|
|
3626
|
+
#tableId = Utilities.generateUuid();
|
|
3087
3627
|
filterRegister;
|
|
3088
|
-
key =
|
|
3628
|
+
key = Utilities.generateUuid();
|
|
3089
3629
|
columnOperator = {};
|
|
3090
3630
|
columnFilter = {};
|
|
3091
3631
|
#localItems = [];
|
|
3092
3632
|
#subscription = new Subscription();
|
|
3633
|
+
#configurationSubscription;
|
|
3634
|
+
#filterRegisterSubscription;
|
|
3635
|
+
#optionInstance;
|
|
3636
|
+
#optionRevision = 0;
|
|
3093
3637
|
#reload = new Subject();
|
|
3094
3638
|
#loadCompleted = false;
|
|
3095
3639
|
cacheValues = {};
|
|
@@ -3099,7 +3643,7 @@ class SdTable {
|
|
|
3099
3643
|
treeRevision = signal(0, ...(ngDevMode ? [{ debugName: "treeRevision" }] : []));
|
|
3100
3644
|
// Search ở cấp con (static tree + type 'local'): predicate khớp 1 dòng theo
|
|
3101
3645
|
// column filter hiện hành. Set ở #filterLocal khi có filter active, đọc lại ở
|
|
3102
|
-
// #render/#
|
|
3646
|
+
// #render/#ensureChildItemsFormatted dùng predicate này để prune + auto-expand các
|
|
3103
3647
|
// nhánh có node con khớp. undefined = không search → cây render bình thường.
|
|
3104
3648
|
#treeSearchPredicate;
|
|
3105
3649
|
// Lần render trước có đang ở chế độ search hay không (để xử lý chuyển trạng thái).
|
|
@@ -3122,27 +3666,40 @@ class SdTable {
|
|
|
3122
3666
|
const option = this.option();
|
|
3123
3667
|
if (option) {
|
|
3124
3668
|
untracked(() => {
|
|
3669
|
+
if (this.#optionInstance !== option) {
|
|
3670
|
+
this.#optionInstance = option;
|
|
3671
|
+
this.#resetStateForNewOption();
|
|
3672
|
+
}
|
|
3673
|
+
const optionRevision = this.#optionRevision;
|
|
3125
3674
|
const initOpt = this.#initConfiguration({ ...option });
|
|
3126
3675
|
this.tableOption.set(initOpt);
|
|
3127
3676
|
this.#loadCompleted = false;
|
|
3128
3677
|
const storage = this.#configService.init(initOpt);
|
|
3129
|
-
this.#
|
|
3678
|
+
this.#configurationSubscription?.unsubscribe();
|
|
3679
|
+
this.#configurationSubscription = storage.observer.pipe(startWith(storage.subject.getValue())).subscribe(() => {
|
|
3680
|
+
if (optionRevision !== this.#optionRevision)
|
|
3681
|
+
return;
|
|
3130
3682
|
const configurationResult = this.#configService.loadConfigurationResult(initOpt, storage.get());
|
|
3131
3683
|
const displayColumns = configurationResult.displayedColumns || [];
|
|
3132
3684
|
this.#ref.detectChanges();
|
|
3133
3685
|
this.#tableFormatService
|
|
3134
3686
|
.loadValues(initOpt.columns.filter(column => displayColumns.includes(column.field)), this.cacheValues, this.#cacheObjValues)
|
|
3135
3687
|
.then(() => {
|
|
3688
|
+
if (optionRevision !== this.#optionRevision)
|
|
3689
|
+
return;
|
|
3136
3690
|
this.configuration.set(configurationResult);
|
|
3137
3691
|
this.#loadFilterRegister();
|
|
3138
3692
|
if (this.filterRegister) {
|
|
3139
|
-
this.#
|
|
3693
|
+
this.#requestReload(true);
|
|
3140
3694
|
}
|
|
3141
3695
|
})
|
|
3142
3696
|
.finally(() => {
|
|
3697
|
+
if (optionRevision !== this.#optionRevision)
|
|
3698
|
+
return;
|
|
3143
3699
|
this.#ref.detectChanges();
|
|
3144
3700
|
});
|
|
3145
|
-
})
|
|
3701
|
+
});
|
|
3702
|
+
this.#subscription.add(this.#configurationSubscription);
|
|
3146
3703
|
});
|
|
3147
3704
|
}
|
|
3148
3705
|
});
|
|
@@ -3150,7 +3707,7 @@ class SdTable {
|
|
|
3150
3707
|
const paginator = this.paginator();
|
|
3151
3708
|
if (paginator) {
|
|
3152
3709
|
untracked(() => {
|
|
3153
|
-
this.#subscription.add(paginator.page.subscribe(() => this.#
|
|
3710
|
+
this.#subscription.add(paginator.page.subscribe(() => this.#requestReload(false)));
|
|
3154
3711
|
});
|
|
3155
3712
|
}
|
|
3156
3713
|
});
|
|
@@ -3158,7 +3715,7 @@ class SdTable {
|
|
|
3158
3715
|
const sort = this.sort();
|
|
3159
3716
|
if (sort) {
|
|
3160
3717
|
untracked(() => {
|
|
3161
|
-
this.#subscription.add(sort.sortChange.subscribe(() => this.#
|
|
3718
|
+
this.#subscription.add(sort.sortChange.subscribe(() => this.#requestReload(false)));
|
|
3162
3719
|
});
|
|
3163
3720
|
}
|
|
3164
3721
|
});
|
|
@@ -3172,7 +3729,7 @@ class SdTable {
|
|
|
3172
3729
|
const conf = this.configuration();
|
|
3173
3730
|
if (!conf)
|
|
3174
3731
|
return;
|
|
3175
|
-
const firstColumns = conf.firstColumns.map(c => c.field === field ? { ...c, width } : c);
|
|
3732
|
+
const firstColumns = conf.firstColumns.map(c => (c.field === field ? { ...c, width } : c));
|
|
3176
3733
|
const column = { ...conf.column };
|
|
3177
3734
|
if (column[field]) {
|
|
3178
3735
|
column[field] = { ...column[field], width };
|
|
@@ -3184,16 +3741,26 @@ class SdTable {
|
|
|
3184
3741
|
this.configuration.set({ ...conf, firstColumns, column, fixedColumn });
|
|
3185
3742
|
}));
|
|
3186
3743
|
}
|
|
3187
|
-
ngOnInit() { }
|
|
3188
3744
|
ngAfterViewInit() {
|
|
3189
3745
|
this.#subscription.add(this.#reload
|
|
3190
3746
|
.pipe(debounceTime(200), switchMap(async (data) => {
|
|
3747
|
+
if (data.revision !== this.#optionRevision || !this.filterRegister)
|
|
3748
|
+
return undefined;
|
|
3191
3749
|
const filterInfo = this.getFilterRequest();
|
|
3192
3750
|
const result = await this.#load(filterInfo, !this.#loadCompleted || data.force);
|
|
3751
|
+
if (data.revision !== this.#optionRevision)
|
|
3752
|
+
return undefined;
|
|
3193
3753
|
this.#loadCompleted = true;
|
|
3194
|
-
return
|
|
3754
|
+
return {
|
|
3755
|
+
result,
|
|
3756
|
+
revision: data.revision,
|
|
3757
|
+
};
|
|
3195
3758
|
}))
|
|
3196
|
-
.subscribe(
|
|
3759
|
+
.subscribe(loadResult => {
|
|
3760
|
+
if (!loadResult || loadResult.revision !== this.#optionRevision)
|
|
3761
|
+
return;
|
|
3762
|
+
this.#render(loadResult.result);
|
|
3763
|
+
}));
|
|
3197
3764
|
}
|
|
3198
3765
|
ngOnDestroy() {
|
|
3199
3766
|
this.#subscription.unsubscribe();
|
|
@@ -3212,6 +3779,49 @@ class SdTable {
|
|
|
3212
3779
|
isExported: true,
|
|
3213
3780
|
};
|
|
3214
3781
|
};
|
|
3782
|
+
#requestReload = (force) => {
|
|
3783
|
+
this.#reload.next({ force, revision: this.#optionRevision });
|
|
3784
|
+
};
|
|
3785
|
+
#resetStateForNewOption = () => {
|
|
3786
|
+
this.#optionRevision += 1;
|
|
3787
|
+
this.#configurationSubscription?.unsubscribe();
|
|
3788
|
+
this.#configurationSubscription = undefined;
|
|
3789
|
+
this.#filterRegisterSubscription?.unsubscribe();
|
|
3790
|
+
this.#filterRegisterSubscription = undefined;
|
|
3791
|
+
this.filterRegister = undefined;
|
|
3792
|
+
this.#tableId = Utilities.generateUuid();
|
|
3793
|
+
this.key = Utilities.generateUuid();
|
|
3794
|
+
this.#loadCompleted = false;
|
|
3795
|
+
this.tableOption.set(undefined);
|
|
3796
|
+
this.configuration.set(undefined);
|
|
3797
|
+
this.items.set([]);
|
|
3798
|
+
this.selectedTableItems.set([]);
|
|
3799
|
+
this.total.set(undefined);
|
|
3800
|
+
this.loading.set(false);
|
|
3801
|
+
this.isSelectAll.set(false);
|
|
3802
|
+
this.isFiltered.set(false);
|
|
3803
|
+
this.requireFiltered.set(false);
|
|
3804
|
+
this.columnOperator = {};
|
|
3805
|
+
this.#syncColumnFilterInPlace({});
|
|
3806
|
+
this.#localItems = [];
|
|
3807
|
+
this.cacheValues = {};
|
|
3808
|
+
this.#cacheObjValues = {};
|
|
3809
|
+
this.#itemIndexMap = new WeakMap();
|
|
3810
|
+
this.#treeExpandState.clear();
|
|
3811
|
+
this.#treeSearchPredicate = undefined;
|
|
3812
|
+
this.#treeSearchActive = false;
|
|
3813
|
+
this.groupExpandState.clear();
|
|
3814
|
+
this.#preservedSelectedMap.clear();
|
|
3815
|
+
this.treeRevision.update(n => n + 1);
|
|
3816
|
+
if (this.paginator()) {
|
|
3817
|
+
this.paginator().pageIndex = 0;
|
|
3818
|
+
}
|
|
3819
|
+
const sort = this.sort();
|
|
3820
|
+
if (sort) {
|
|
3821
|
+
sort.active = '';
|
|
3822
|
+
sort.direction = '';
|
|
3823
|
+
}
|
|
3824
|
+
};
|
|
3215
3825
|
#initConfiguration = (option) => {
|
|
3216
3826
|
option.paginate = {
|
|
3217
3827
|
hidden: option?.paginate?.hidden,
|
|
@@ -3231,7 +3841,10 @@ class SdTable {
|
|
|
3231
3841
|
if (!column.filter?.operator?.list?.length) {
|
|
3232
3842
|
column.filter.operator.list = this.tableConfiguration?.filter?.operator?.list?.[column.type] || [];
|
|
3233
3843
|
}
|
|
3234
|
-
|
|
3844
|
+
const defaultOperator = this.tableConfiguration?.filter?.operator?.default?.[column.type];
|
|
3845
|
+
if (defaultOperator) {
|
|
3846
|
+
this.columnOperator[column.field] = defaultOperator;
|
|
3847
|
+
}
|
|
3235
3848
|
if (column.filter.operator.default && column.filter.operator.list?.some(el => el === column.filter?.operator?.default)) {
|
|
3236
3849
|
this.columnOperator[column.field] = column.filter.operator.default;
|
|
3237
3850
|
}
|
|
@@ -3241,33 +3854,39 @@ class SdTable {
|
|
|
3241
3854
|
};
|
|
3242
3855
|
#loadFilterRegister = () => {
|
|
3243
3856
|
const opt = this.tableOption();
|
|
3244
|
-
if (opt
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3857
|
+
if (!opt || this.filterRegister)
|
|
3858
|
+
return;
|
|
3859
|
+
this.filterRegister = this.#gridFilterService.register(opt?.filter, {
|
|
3860
|
+
id: this.#tableId,
|
|
3861
|
+
columns: opt?.columns,
|
|
3862
|
+
externalFilters: opt?.filter?.externalFilters,
|
|
3863
|
+
filterDefs: [...this.sdFilterDefs()],
|
|
3864
|
+
columnOperator: this.columnOperator,
|
|
3865
|
+
force: true,
|
|
3866
|
+
});
|
|
3867
|
+
const { columnOperator, columnFilter } = this.filterRegister.value.get();
|
|
3868
|
+
this.columnOperator = columnOperator || {};
|
|
3869
|
+
this.#syncColumnFilterInPlace(columnFilter || {});
|
|
3870
|
+
this.#filterRegisterSubscription?.unsubscribe();
|
|
3871
|
+
this.#filterRegisterSubscription = this.filterRegister.value.observer
|
|
3872
|
+
.pipe(debounceTime(500), map(filterValue => {
|
|
3873
|
+
const { columnOperator, columnFilter, notReload } = filterValue;
|
|
3874
|
+
this.columnOperator = columnOperator || {};
|
|
3875
|
+
// Sync IN PLACE — không gán object clone mới. column-filter chia sẻ
|
|
3876
|
+
// reference this.columnFilter qua [columnFilter] input; nếu gán clone
|
|
3877
|
+
// mới, cf giữ ref cũ (do OnPush + reload async lag) → ghi clear vào
|
|
3878
|
+
// object orphan → giá trị cũ persist. Giữ ref ổn định để cf + table
|
|
3879
|
+
// luôn trỏ cùng 1 object.
|
|
3880
|
+
this.#syncColumnFilterInPlace(columnFilter || {});
|
|
3881
|
+
if (!notReload) {
|
|
3882
|
+
if (this.paginator()) {
|
|
3883
|
+
this.paginator().pageIndex = 0;
|
|
3267
3884
|
}
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
}
|
|
3885
|
+
this.#requestReload(false);
|
|
3886
|
+
}
|
|
3887
|
+
}))
|
|
3888
|
+
.subscribe();
|
|
3889
|
+
this.#subscription.add(this.#filterRegisterSubscription);
|
|
3271
3890
|
};
|
|
3272
3891
|
// Đồng bộ this.columnFilter với `next` mà GIỮ NGUYÊN reference object.
|
|
3273
3892
|
// column-filter chia sẻ ref này qua [columnFilter] — reassign clone mới sẽ
|
|
@@ -3282,158 +3901,12 @@ class SdTable {
|
|
|
3282
3901
|
}
|
|
3283
3902
|
Object.assign(cur, next);
|
|
3284
3903
|
};
|
|
3285
|
-
// True nếu column filter hiện có ít nhất một giá trị đang lọc (để bật search-con).
|
|
3286
|
-
#hasActiveColumnFilter = (rawColumnFilter, columns) => columns.some(col => {
|
|
3287
|
-
const v = rawColumnFilter[col.field];
|
|
3288
|
-
if (Array.isArray(v))
|
|
3289
|
-
return v.length > 0;
|
|
3290
|
-
if (v && typeof v === 'object')
|
|
3291
|
-
return !!v.from || !!v.to;
|
|
3292
|
-
return v !== undefined && v !== null && v !== '';
|
|
3293
|
-
});
|
|
3294
|
-
// Predicate khớp MỘT dòng (raw data) theo column filter. Tách riêng để dùng lại
|
|
3295
|
-
// cho cả lọc root lẫn search-con (subtreeMatches/filterMatchingChildren).
|
|
3296
|
-
#matchesColumnFilter = (data, columns, rawColumnFilter) => {
|
|
3297
|
-
for (const column of columns) {
|
|
3298
|
-
const { field, type } = column;
|
|
3299
|
-
const filterValue = (rawColumnFilter[field] || '').toString().trim().toLowerCase();
|
|
3300
|
-
// SỬA: Dùng getNestedValue để hỗ trợ nested field trong filterLocal
|
|
3301
|
-
const rawColVal = Utilities.getNestedValue(data, field);
|
|
3302
|
-
const columnValue = (rawColVal || '').toString().trim().toLowerCase();
|
|
3303
|
-
if (filterValue) {
|
|
3304
|
-
if (!columnValue && type !== 'datetime' && type !== 'date' && type !== 'time') {
|
|
3305
|
-
return false;
|
|
3306
|
-
}
|
|
3307
|
-
if (type === 'string') {
|
|
3308
|
-
if (columnValue.indexOf(filterValue) === -1) {
|
|
3309
|
-
return false;
|
|
3310
|
-
}
|
|
3311
|
-
}
|
|
3312
|
-
else if (type === 'values' || type === 'lazy-values') {
|
|
3313
|
-
const columnType = column;
|
|
3314
|
-
const isMultiple = columnType.option.selection === 'MULTIPLE';
|
|
3315
|
-
if (isMultiple && Array.isArray(rawColVal)) {
|
|
3316
|
-
const columnValues = rawColVal.map((i) => (Utilities.getNestedValue(i, columnType.option.valueField) ?? '').toString().trim().toLowerCase()) ?? [];
|
|
3317
|
-
const filterValues = rawColumnFilter[field]?.map((v) => (v ?? '').toString().trim().toLowerCase());
|
|
3318
|
-
if (filterValues?.length && filterValues.every(fv => !columnValues.includes(fv))) {
|
|
3319
|
-
return false;
|
|
3320
|
-
}
|
|
3321
|
-
}
|
|
3322
|
-
else {
|
|
3323
|
-
if (columnValue !== filterValue) {
|
|
3324
|
-
return false;
|
|
3325
|
-
}
|
|
3326
|
-
}
|
|
3327
|
-
}
|
|
3328
|
-
else if (type === 'number') {
|
|
3329
|
-
const fValue = +filterValue.replace('>=', '').replace('<=', '').replace('>', '').replace('<', '');
|
|
3330
|
-
const cValue = +columnValue;
|
|
3331
|
-
if (fValue || fValue === 0) {
|
|
3332
|
-
if (!cValue && cValue !== 0) {
|
|
3333
|
-
return false;
|
|
3334
|
-
}
|
|
3335
|
-
if (filterValue.indexOf('>=') > -1 && cValue < fValue) {
|
|
3336
|
-
return false;
|
|
3337
|
-
}
|
|
3338
|
-
else if (filterValue.indexOf('<=') > -1 && cValue > fValue) {
|
|
3339
|
-
return false;
|
|
3340
|
-
}
|
|
3341
|
-
else if (filterValue.indexOf('<') > -1 && cValue >= fValue) {
|
|
3342
|
-
return false;
|
|
3343
|
-
}
|
|
3344
|
-
else if (filterValue.indexOf('>') > -1 && cValue <= fValue) {
|
|
3345
|
-
return false;
|
|
3346
|
-
}
|
|
3347
|
-
else if (cValue !== fValue) {
|
|
3348
|
-
return false;
|
|
3349
|
-
}
|
|
3350
|
-
}
|
|
3351
|
-
}
|
|
3352
|
-
else if (type === 'boolean') {
|
|
3353
|
-
if ((filterValue === '1' || filterValue === 'true') && columnValue !== '1' && columnValue !== 'true') {
|
|
3354
|
-
return false;
|
|
3355
|
-
}
|
|
3356
|
-
else if ((filterValue === '0' || filterValue === 'false') && columnValue !== '0' && columnValue !== 'false') {
|
|
3357
|
-
return false;
|
|
3358
|
-
}
|
|
3359
|
-
}
|
|
3360
|
-
else if (type === 'datetime' || type === 'date' || type === 'time') {
|
|
3361
|
-
const from = rawColumnFilter[field]?.from ?? rawColumnFilter[field];
|
|
3362
|
-
const to = rawColumnFilter[field]?.to ?? rawColumnFilter[field];
|
|
3363
|
-
const fromDate = DateUtilities.begin(from);
|
|
3364
|
-
const toDate = DateUtilities.end(to);
|
|
3365
|
-
if (fromDate || toDate) {
|
|
3366
|
-
if (!columnValue) {
|
|
3367
|
-
return false;
|
|
3368
|
-
}
|
|
3369
|
-
const columnTime = new Date(columnValue).getTime();
|
|
3370
|
-
const fromDateTime = fromDate?.getTime() || null;
|
|
3371
|
-
const toDateTime = toDate?.getTime() || null;
|
|
3372
|
-
if (fromDateTime && fromDateTime > columnTime) {
|
|
3373
|
-
return false;
|
|
3374
|
-
}
|
|
3375
|
-
if (toDateTime && columnTime > toDateTime) {
|
|
3376
|
-
return false;
|
|
3377
|
-
}
|
|
3378
|
-
}
|
|
3379
|
-
}
|
|
3380
|
-
}
|
|
3381
|
-
}
|
|
3382
|
-
return true;
|
|
3383
|
-
};
|
|
3384
3904
|
#filterLocal = (localItems, filterInfo) => {
|
|
3385
|
-
const
|
|
3386
|
-
|
|
3387
|
-
const { rawColumnFilter, orderBy, orderDirection, pageSize, pageNumber } = filterInfo;
|
|
3388
|
-
const matchesData = (data) => this.#matchesColumnFilter(data, columns, rawColumnFilter);
|
|
3389
|
-
// Search ở cấp con: chỉ bật cho table local + static tree + đang có filter.
|
|
3390
|
-
// Khi bật, một root được giữ nếu CHÍNH NÓ hoặc bất kỳ hậu duệ nào khớp; và
|
|
3391
|
-
// lưu predicate để #render prune + auto-expand nhánh khớp.
|
|
3392
|
-
const treeOpt = opt.tree;
|
|
3393
|
-
const treeSearch = opt.type === 'local' && treeOpt?.loadType === 'static' && this.#hasActiveColumnFilter(rawColumnFilter, columns);
|
|
3394
|
-
this.#treeSearchPredicate = treeSearch ? matchesData : undefined;
|
|
3395
|
-
const items = treeSearch
|
|
3396
|
-
? localItems.filter(tableItem => subtreeMatches(tableItem.data, matchesData, treeOpt))
|
|
3397
|
-
: localItems.filter(tableItem => matchesData(tableItem.data));
|
|
3398
|
-
// Sort
|
|
3399
|
-
if (orderBy && orderDirection) {
|
|
3400
|
-
const column = columns.find(e => e.field === orderBy);
|
|
3401
|
-
if (column) {
|
|
3402
|
-
const { type, field } = column;
|
|
3403
|
-
items.sort((tableItemCurrent, tableItemNext) => {
|
|
3404
|
-
const data = tableItemCurrent.data;
|
|
3405
|
-
const next = tableItemNext.data;
|
|
3406
|
-
// SỬA: Dùng getNestedValue cho sorting
|
|
3407
|
-
const dataVal = Utilities.getNestedValue(data, field);
|
|
3408
|
-
const nextVal = Utilities.getNestedValue(next, field);
|
|
3409
|
-
if (type === 'number') {
|
|
3410
|
-
return (dataVal || 0) - (nextVal || 0);
|
|
3411
|
-
}
|
|
3412
|
-
if (type === 'date' || type === 'datetime' || type === 'time') {
|
|
3413
|
-
const d1 = new Date(dataVal || '').getTime();
|
|
3414
|
-
const d2 = new Date(nextVal || '').getTime();
|
|
3415
|
-
return d1 - d2;
|
|
3416
|
-
}
|
|
3417
|
-
const s1 = (dataVal || '').toString();
|
|
3418
|
-
const s2 = (nextVal || '').toString();
|
|
3419
|
-
if (s1 > s2) {
|
|
3420
|
-
return 1;
|
|
3421
|
-
}
|
|
3422
|
-
if (s1 < s2) {
|
|
3423
|
-
return -1;
|
|
3424
|
-
}
|
|
3425
|
-
return 0;
|
|
3426
|
-
});
|
|
3427
|
-
if (orderDirection === 'DESC') {
|
|
3428
|
-
items.reverse();
|
|
3429
|
-
}
|
|
3430
|
-
}
|
|
3431
|
-
}
|
|
3905
|
+
const result = filterLocalItems(localItems, this.tableOption(), filterInfo);
|
|
3906
|
+
this.#treeSearchPredicate = result.treeSearchPredicate;
|
|
3432
3907
|
return {
|
|
3433
|
-
items: items
|
|
3434
|
-
|
|
3435
|
-
}),
|
|
3436
|
-
total: items.length,
|
|
3908
|
+
items: result.items,
|
|
3909
|
+
total: result.total,
|
|
3437
3910
|
};
|
|
3438
3911
|
};
|
|
3439
3912
|
getFilterRequest = () => {
|
|
@@ -3517,7 +3990,10 @@ class SdTable {
|
|
|
3517
3990
|
total: 0,
|
|
3518
3991
|
};
|
|
3519
3992
|
}
|
|
3520
|
-
const pagingReq =
|
|
3993
|
+
const pagingReq = SdConvertToPagingReq(filterReq, {
|
|
3994
|
+
columns: opt.columns,
|
|
3995
|
+
externalFilters: opt.filter?.externalFilters,
|
|
3996
|
+
});
|
|
3521
3997
|
const data = await items(filterReq, pagingReq).catch(err => {
|
|
3522
3998
|
console.error(err);
|
|
3523
3999
|
return {
|
|
@@ -3567,18 +4043,21 @@ class SdTable {
|
|
|
3567
4043
|
// why: KHÔNG persist trạng thái bung bị ÉP trong lúc search (tránh nhánh
|
|
3568
4044
|
// tự bung do search bị ghi nhầm thành lựa chọn của user sau khi clear).
|
|
3569
4045
|
if (!this.#treeSearchActive) {
|
|
3570
|
-
|
|
4046
|
+
saveTreeExpandState(this.items(), this.#treeExpandState);
|
|
3571
4047
|
}
|
|
3572
4048
|
// why: search vừa tắt → childItems đang là tập đã prune theo từ khoá cũ;
|
|
3573
4049
|
// xoá cache để dựng lại đầy đủ children ở chế độ thường.
|
|
3574
4050
|
if (this.#treeSearchActive && !searchNow) {
|
|
3575
|
-
|
|
4051
|
+
clearTreeChildCache(this.#localItems);
|
|
3576
4052
|
}
|
|
3577
4053
|
}
|
|
3578
4054
|
this.items.set(args?.items || []);
|
|
3579
4055
|
this.total.set(args?.total || 0);
|
|
3580
4056
|
if (treeOpt) {
|
|
3581
|
-
|
|
4057
|
+
initTreeMeta(this.items(), treeOpt, {
|
|
4058
|
+
expandState: this.#treeExpandState,
|
|
4059
|
+
treeSearchPredicate: this.#treeSearchPredicate,
|
|
4060
|
+
});
|
|
3582
4061
|
await this.#expandDefaultBranches(this.items(), treeOpt);
|
|
3583
4062
|
this.treeRevision.update(n => n + 1);
|
|
3584
4063
|
}
|
|
@@ -3625,7 +4104,10 @@ class SdTable {
|
|
|
3625
4104
|
else {
|
|
3626
4105
|
const filterReq = this.#filterExportInfo(pageNumber, pageSize);
|
|
3627
4106
|
if (opt.type === 'server') {
|
|
3628
|
-
const pagingReq =
|
|
4107
|
+
const pagingReq = SdConvertToPagingReq(filterReq, {
|
|
4108
|
+
columns: opt.columns,
|
|
4109
|
+
externalFilters: opt.filter?.externalFilters,
|
|
4110
|
+
});
|
|
3629
4111
|
const result = opt.items(filterReq, pagingReq);
|
|
3630
4112
|
return await result;
|
|
3631
4113
|
}
|
|
@@ -3670,51 +4152,6 @@ class SdTable {
|
|
|
3670
4152
|
exportCustom = () => {
|
|
3671
4153
|
this.#tableExportService.exportCustom(this.#createExportContext());
|
|
3672
4154
|
};
|
|
3673
|
-
#saveTreeExpandState = (rows) => {
|
|
3674
|
-
for (const row of rows) {
|
|
3675
|
-
if (row.meta.tree?.isExpanded) {
|
|
3676
|
-
this.#treeExpandState.set(row.meta.id, true);
|
|
3677
|
-
}
|
|
3678
|
-
for (const child of row.meta.tree?.childItems ?? []) {
|
|
3679
|
-
this.#saveTreeExpandState([child]);
|
|
3680
|
-
}
|
|
3681
|
-
}
|
|
3682
|
-
};
|
|
3683
|
-
// Children "nhìn thấy được" của một row: bình thường = toàn bộ embedded;
|
|
3684
|
-
// khi search-con = chỉ giữ child có subtree khớp từ khoá (prune).
|
|
3685
|
-
#visibleChildrenData = (data, treeOpt) => {
|
|
3686
|
-
const all = getChildrenFromData(data, treeOpt);
|
|
3687
|
-
const predicate = this.#treeSearchPredicate;
|
|
3688
|
-
return predicate ? filterMatchingChildren(all, predicate, treeOpt) : all;
|
|
3689
|
-
};
|
|
3690
|
-
// Xoá cache childItems trên toàn cây — dùng khi tắt search để dựng lại đầy đủ.
|
|
3691
|
-
#clearTreeChildCache = (rows) => {
|
|
3692
|
-
for (const row of rows) {
|
|
3693
|
-
const children = row.meta.tree?.childItems;
|
|
3694
|
-
if (children?.length) {
|
|
3695
|
-
this.#clearTreeChildCache(children);
|
|
3696
|
-
row.meta.tree.childItems = undefined;
|
|
3697
|
-
}
|
|
3698
|
-
}
|
|
3699
|
-
};
|
|
3700
|
-
#initTreeMeta = (rows, option, level = 0, parentId) => {
|
|
3701
|
-
const searchActive = !!this.#treeSearchPredicate;
|
|
3702
|
-
for (const row of rows) {
|
|
3703
|
-
const saved = this.#treeExpandState.get(row.meta.id);
|
|
3704
|
-
// Khi search: hasChildren tính theo tập con đã prune; auto-expand nhánh còn con.
|
|
3705
|
-
const hasChildren = searchActive
|
|
3706
|
-
? this.#visibleChildrenData(row.data, option).length > 0
|
|
3707
|
-
: resolveHasChildren(row, option);
|
|
3708
|
-
row.meta.tree = {
|
|
3709
|
-
...row.meta.tree,
|
|
3710
|
-
level,
|
|
3711
|
-
parentId,
|
|
3712
|
-
hasChildren,
|
|
3713
|
-
isExpanded: searchActive ? hasChildren : (saved ?? resolveDefaultExpanded(level, option)),
|
|
3714
|
-
isExpanding: false,
|
|
3715
|
-
};
|
|
3716
|
-
}
|
|
3717
|
-
};
|
|
3718
4155
|
#ensureChildItemsFormatted = async (row) => {
|
|
3719
4156
|
const opt = this.tableOption();
|
|
3720
4157
|
const treeOpt = opt.tree;
|
|
@@ -3723,7 +4160,7 @@ class SdTable {
|
|
|
3723
4160
|
// vì tập này phụ thuộc từ khoá (đổi mỗi lần gõ) nên không thể cache.
|
|
3724
4161
|
if (!searchActive && row.meta.tree?.childItems?.length)
|
|
3725
4162
|
return;
|
|
3726
|
-
const raw =
|
|
4163
|
+
const raw = getVisibleChildrenData(row.data, treeOpt, this.#treeSearchPredicate);
|
|
3727
4164
|
if (!raw.length) {
|
|
3728
4165
|
if (searchActive && row.meta.tree)
|
|
3729
4166
|
row.meta.tree.childItems = [];
|
|
@@ -3731,20 +4168,12 @@ class SdTable {
|
|
|
3731
4168
|
}
|
|
3732
4169
|
const formatted = await this.#tableFormatService.format(raw, opt.columns, this.cacheValues, this.#cacheObjValues);
|
|
3733
4170
|
row.meta.tree.childItems = formatted;
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
child.meta.tree = {
|
|
3741
|
-
level: childLevel,
|
|
3742
|
-
parentId: row.meta.id,
|
|
3743
|
-
hasChildren: childHasChildren,
|
|
3744
|
-
isExpanded: searchActive ? childHasChildren : (saved ?? resolveDefaultExpanded(childLevel, treeOpt)),
|
|
3745
|
-
isExpanding: false,
|
|
3746
|
-
};
|
|
3747
|
-
}
|
|
4171
|
+
initTreeMeta(formatted, treeOpt, {
|
|
4172
|
+
level: (row.meta.tree.level ?? 0) + 1,
|
|
4173
|
+
parentId: row.meta.id,
|
|
4174
|
+
expandState: this.#treeExpandState,
|
|
4175
|
+
treeSearchPredicate: this.#treeSearchPredicate,
|
|
4176
|
+
});
|
|
3748
4177
|
};
|
|
3749
4178
|
#expandDefaultBranches = async (rows, option) => {
|
|
3750
4179
|
const maxDepth = option.maxDepth;
|
|
@@ -3903,28 +4332,14 @@ class SdTable {
|
|
|
3903
4332
|
this.#updateSelectedItems();
|
|
3904
4333
|
};
|
|
3905
4334
|
#getSelectionRows = () => {
|
|
3906
|
-
|
|
3907
|
-
const treeOpt = this.tableOption()?.tree;
|
|
3908
|
-
if (!treeOpt)
|
|
3909
|
-
return roots;
|
|
3910
|
-
return flattenTree(roots, treeOpt);
|
|
4335
|
+
return getSelectionRows(this.items(), this.tableOption()?.tree);
|
|
3911
4336
|
};
|
|
3912
|
-
#getSelectedRowData = () => this.#getSelectionRows()
|
|
3913
|
-
.filter(e => e.meta.selector.isSelected)
|
|
3914
|
-
.map(e => e.data);
|
|
4337
|
+
#getSelectedRowData = () => getSelectedRowData(this.#getSelectionRows());
|
|
3915
4338
|
#applyDefaultSelected = () => {
|
|
3916
|
-
|
|
3917
|
-
if (!defaultSelected)
|
|
3918
|
-
return;
|
|
3919
|
-
const treeOpt = this.tableOption()?.tree;
|
|
3920
|
-
const rows = treeOpt ? collectFormattedTreeRows(this.items()) : this.items();
|
|
3921
|
-
rows.forEach(item => {
|
|
3922
|
-
item.meta.selector.isSelected = defaultSelected(item.data);
|
|
3923
|
-
});
|
|
4339
|
+
applyDefaultSelected(this.items(), this.tableOption()?.tree, this.tableOption()?.selector?.defaultSelected);
|
|
3924
4340
|
};
|
|
3925
4341
|
#syncSelectAllState = () => {
|
|
3926
|
-
|
|
3927
|
-
this.isSelectAll.set(visible.length > 0 && visible.every(e => e.meta.selector?.isSelected));
|
|
4342
|
+
this.isSelectAll.set(resolveSelectAllState(this.#getSelectionRows()));
|
|
3928
4343
|
};
|
|
3929
4344
|
// ==========================================
|
|
3930
4345
|
// GROUP HELPERS — sync selection + expand state cho group header rows
|
|
@@ -3967,9 +4382,7 @@ class SdTable {
|
|
|
3967
4382
|
return;
|
|
3968
4383
|
const key = header.meta.group.key;
|
|
3969
4384
|
const defaultExpanded = !this.tableOption()?.group?.defaultCollapsed;
|
|
3970
|
-
const current = this.groupExpandState.has(key)
|
|
3971
|
-
? !!this.groupExpandState.get(key)
|
|
3972
|
-
: defaultExpanded;
|
|
4385
|
+
const current = this.groupExpandState.has(key) ? !!this.groupExpandState.get(key) : defaultExpanded;
|
|
3973
4386
|
this.groupExpandState.set(key, !current);
|
|
3974
4387
|
header.meta.group.isExpanded = !current;
|
|
3975
4388
|
// why: trigger pipe re-eval — Map mutation không thay đổi reference items() nên cần update.
|
|
@@ -3986,7 +4399,7 @@ class SdTable {
|
|
|
3986
4399
|
* Colspan cho cell sdGroupHeader trên group row = displayedColumns.length.
|
|
3987
4400
|
* Span TOÀN BỘ width data row vì group row chỉ có 1 cell.
|
|
3988
4401
|
*/
|
|
3989
|
-
sdGroupColspan = computed(() =>
|
|
4402
|
+
sdGroupColspan = computed(() => this.configuration()?.displayedColumns?.length || 1, ...(ngDevMode ? [{ debugName: "sdGroupColspan" }] : []));
|
|
3990
4403
|
/** Build context object truyền vào SdTableGroupDefDirective template. */
|
|
3991
4404
|
groupContext = (header) => {
|
|
3992
4405
|
const g = header.meta.group;
|
|
@@ -4008,9 +4421,7 @@ class SdTable {
|
|
|
4008
4421
|
if (!fn)
|
|
4009
4422
|
return null;
|
|
4010
4423
|
const tree = row.meta?.tree;
|
|
4011
|
-
const ctx = this.tableOption()?.tree && tree
|
|
4012
|
-
? { level: tree.level, hasChildren: tree.hasChildren, isExpanded: tree.isExpanded }
|
|
4013
|
-
: undefined;
|
|
4424
|
+
const ctx = this.tableOption()?.tree && tree ? { level: tree.level, hasChildren: tree.hasChildren, isExpanded: tree.isExpanded } : undefined;
|
|
4014
4425
|
return fn(row.data, index, ctx);
|
|
4015
4426
|
};
|
|
4016
4427
|
// why: khi preserveSelection bật, giữ map nội bộ id → SdTableItem để selection
|
|
@@ -4024,29 +4435,14 @@ class SdTable {
|
|
|
4024
4435
|
#restorePreservedSelection = () => {
|
|
4025
4436
|
if (!this.#preserveEnabled())
|
|
4026
4437
|
return;
|
|
4027
|
-
|
|
4028
|
-
rows.forEach(item => {
|
|
4029
|
-
if (this.#preservedSelectedMap.has(item.meta.id)) {
|
|
4030
|
-
item.meta.selector.isSelected = true;
|
|
4031
|
-
this.#preservedSelectedMap.set(item.meta.id, item);
|
|
4032
|
-
}
|
|
4033
|
-
});
|
|
4438
|
+
restorePreservedSelection(this.#getSelectionRows(), this.#preservedSelectedMap);
|
|
4034
4439
|
};
|
|
4035
4440
|
#updateSelectedItems = () => {
|
|
4036
4441
|
const rows = this.#getSelectionRows();
|
|
4037
4442
|
if (this.#preserveEnabled()) {
|
|
4038
4443
|
// Sync map theo state visible: add nếu selected, remove nếu deselected.
|
|
4039
4444
|
// Off-page items giữ nguyên trong map (không bị visit ở đây).
|
|
4040
|
-
|
|
4041
|
-
const id = item.meta.id;
|
|
4042
|
-
if (item.meta.selector.isSelected) {
|
|
4043
|
-
this.#preservedSelectedMap.set(id, item);
|
|
4044
|
-
}
|
|
4045
|
-
else {
|
|
4046
|
-
this.#preservedSelectedMap.delete(id);
|
|
4047
|
-
}
|
|
4048
|
-
});
|
|
4049
|
-
this.selectedTableItems.set(Array.from(this.#preservedSelectedMap.values()));
|
|
4445
|
+
this.selectedTableItems.set(syncPreservedSelection(rows, this.#preservedSelectedMap));
|
|
4050
4446
|
}
|
|
4051
4447
|
else {
|
|
4052
4448
|
this.selectedTableItems.set(rows.filter(item => item.meta.selector.isSelected));
|
|
@@ -4098,295 +4494,38 @@ class SdTable {
|
|
|
4098
4494
|
return (p?.pageIndex ?? 0) * (p?.pageSize ?? 0);
|
|
4099
4495
|
}, ...(ngDevMode ? [{ debugName: "pageOffset" }] : []));
|
|
4100
4496
|
isReorderDisabled(item) {
|
|
4101
|
-
if ((item.meta.tree?.level ?? 0) > 0)
|
|
4102
|
-
return true;
|
|
4103
4497
|
const opt = this.tableOption()?.rowReorder;
|
|
4104
|
-
if (!opt?.disabled || item.meta?.group?.items?.length)
|
|
4105
|
-
return false;
|
|
4106
4498
|
const idx = this.#itemIndexMap.get(item) ?? -1;
|
|
4107
|
-
return
|
|
4108
|
-
}
|
|
4109
|
-
#sameGroup(a, b, allItems) {
|
|
4110
|
-
const groupOf = (item) => {
|
|
4111
|
-
let lastGroupIdx = -1;
|
|
4112
|
-
for (let i = 0; i < allItems.length; i++) {
|
|
4113
|
-
if (allItems[i].meta?.group?.items?.length)
|
|
4114
|
-
lastGroupIdx = i;
|
|
4115
|
-
if (allItems[i] === item)
|
|
4116
|
-
return lastGroupIdx;
|
|
4117
|
-
}
|
|
4118
|
-
return -1;
|
|
4119
|
-
};
|
|
4120
|
-
return groupOf(a) === groupOf(b);
|
|
4499
|
+
return isReorderDisabled(item, opt, idx);
|
|
4121
4500
|
}
|
|
4122
4501
|
reorderSortPredicate = (index, drag, drop) => {
|
|
4123
4502
|
const opt = this.tableOption()?.rowReorder;
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
return false;
|
|
4132
|
-
if ((drag.data.meta.tree?.level ?? 0) > 0)
|
|
4133
|
-
return false;
|
|
4134
|
-
if (targetItem.meta?.group?.items?.length)
|
|
4135
|
-
return false;
|
|
4136
|
-
if (this.tableOption()?.group) {
|
|
4137
|
-
return this.#sameGroup(drag.data, targetItem, allItems);
|
|
4138
|
-
}
|
|
4139
|
-
return true;
|
|
4503
|
+
return canSortReorder({
|
|
4504
|
+
enabled: opt?.enabled,
|
|
4505
|
+
index,
|
|
4506
|
+
dragItem: drag.data,
|
|
4507
|
+
allItems: drop.data,
|
|
4508
|
+
hasGroup: !!this.tableOption()?.group,
|
|
4509
|
+
});
|
|
4140
4510
|
};
|
|
4141
4511
|
onReorderDrop(event) {
|
|
4142
4512
|
const { previousIndex, currentIndex } = event;
|
|
4143
4513
|
if (previousIndex === currentIndex)
|
|
4144
4514
|
return;
|
|
4145
|
-
const
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
const toIdx = toItemsIndex(currentIndex);
|
|
4156
|
-
const current = [...this.items()];
|
|
4157
|
-
const localPositions = current.map(item => this.#localItems.indexOf(item));
|
|
4158
|
-
moveItemInArray(current, fromIdx, toIdx);
|
|
4159
|
-
this.items.set(current);
|
|
4160
|
-
if (this.tableOption()?.type === 'local' && localPositions.every(p => p >= 0)) {
|
|
4161
|
-
const newLocal = [...this.#localItems];
|
|
4162
|
-
current.forEach((item, i) => {
|
|
4163
|
-
newLocal[localPositions[i]] = item;
|
|
4164
|
-
});
|
|
4165
|
-
this.#localItems = newLocal;
|
|
4515
|
+
const result = reorderTableItems({
|
|
4516
|
+
items: this.items(),
|
|
4517
|
+
renderedItems: event.container.data,
|
|
4518
|
+
previousRenderedIndex: previousIndex,
|
|
4519
|
+
currentRenderedIndex: currentIndex,
|
|
4520
|
+
localItems: this.tableOption()?.type === 'local' ? this.#localItems : undefined,
|
|
4521
|
+
});
|
|
4522
|
+
this.items.set(result.items);
|
|
4523
|
+
if (this.tableOption()?.type === 'local' && result.localItems) {
|
|
4524
|
+
this.#localItems = result.localItems;
|
|
4166
4525
|
}
|
|
4167
4526
|
this.table()?.renderRows();
|
|
4168
|
-
this.tableOption()?.rowReorder?.onChange?.(
|
|
4527
|
+
this.tableOption()?.rowReorder?.onChange?.(result.items.map(i => i.data), event.item.data.data, result.fromIndex, result.toIndex);
|
|
4169
4528
|
}
|
|
4170
|
-
#convertPagingReq = (filterReq) => {
|
|
4171
|
-
const opt = this.tableOption();
|
|
4172
|
-
const { columns, filter } = opt;
|
|
4173
|
-
const externalFilters = filter?.externalFilters || [];
|
|
4174
|
-
const req = {
|
|
4175
|
-
filters: [],
|
|
4176
|
-
orders: [],
|
|
4177
|
-
pageNumber: filterReq.pageNumber,
|
|
4178
|
-
pageSize: filterReq.pageSize,
|
|
4179
|
-
};
|
|
4180
|
-
const { filters, orders } = req;
|
|
4181
|
-
const { rawColumnFilter, columnOperator, rawExternalFilter, orderBy, orderDirection } = filterReq;
|
|
4182
|
-
for (const externalFilter of externalFilters || []) {
|
|
4183
|
-
const { field } = externalFilter;
|
|
4184
|
-
const value = rawExternalFilter?.[field];
|
|
4185
|
-
if (value !== undefined && value !== null && value !== '') {
|
|
4186
|
-
if (externalFilter.type === 'string') {
|
|
4187
|
-
if (externalFilter.defaultOperator === 'EQUAL' && value?.includes(',')) {
|
|
4188
|
-
filters.push({
|
|
4189
|
-
field,
|
|
4190
|
-
operator: 'IN',
|
|
4191
|
-
data: value.split(',').map(val => val.trim()),
|
|
4192
|
-
});
|
|
4193
|
-
}
|
|
4194
|
-
else {
|
|
4195
|
-
filters.push({
|
|
4196
|
-
field,
|
|
4197
|
-
operator: externalFilter.defaultOperator || 'CONTAIN',
|
|
4198
|
-
data: value,
|
|
4199
|
-
});
|
|
4200
|
-
}
|
|
4201
|
-
}
|
|
4202
|
-
else if (externalFilter.type === 'boolean') {
|
|
4203
|
-
filters.push({
|
|
4204
|
-
field,
|
|
4205
|
-
operator: 'EQUAL',
|
|
4206
|
-
data: value === true || value === 1 || value === 'true' || value === '1',
|
|
4207
|
-
});
|
|
4208
|
-
}
|
|
4209
|
-
else if (externalFilter.type === 'daterange') {
|
|
4210
|
-
if (typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
4211
|
-
if (value?.from) {
|
|
4212
|
-
filters.push({
|
|
4213
|
-
field,
|
|
4214
|
-
operator: 'GREATER_OR_EQUAL',
|
|
4215
|
-
data: DateUtilities.begin(value?.from).toISOString(),
|
|
4216
|
-
});
|
|
4217
|
-
}
|
|
4218
|
-
if (value?.to) {
|
|
4219
|
-
filters.push({
|
|
4220
|
-
field,
|
|
4221
|
-
operator: 'LESS_THAN',
|
|
4222
|
-
data: DateUtilities.begin(DateUtilities.addDays(value?.to, 1)).toISOString(),
|
|
4223
|
-
});
|
|
4224
|
-
}
|
|
4225
|
-
}
|
|
4226
|
-
}
|
|
4227
|
-
else if (externalFilter.type === 'date' || externalFilter.type === 'datetime') {
|
|
4228
|
-
if (DateUtilities.isDate(value)) {
|
|
4229
|
-
if (externalFilter.type === 'date') {
|
|
4230
|
-
if (externalFilter.defaultOperator === 'GREATER_OR_EQUAL') {
|
|
4231
|
-
filters.push({
|
|
4232
|
-
field,
|
|
4233
|
-
operator: 'GREATER_OR_EQUAL',
|
|
4234
|
-
data: DateUtilities.begin(value).toISOString(),
|
|
4235
|
-
});
|
|
4236
|
-
}
|
|
4237
|
-
if (externalFilter.defaultOperator === 'LESS_OR_EQUAL') {
|
|
4238
|
-
filters.push({
|
|
4239
|
-
field,
|
|
4240
|
-
operator: 'LESS_THAN',
|
|
4241
|
-
data: DateUtilities.begin(DateUtilities.addDays(value, 1)).toISOString(),
|
|
4242
|
-
});
|
|
4243
|
-
}
|
|
4244
|
-
}
|
|
4245
|
-
else {
|
|
4246
|
-
if (externalFilter.defaultOperator === 'GREATER_OR_EQUAL') {
|
|
4247
|
-
filters.push({
|
|
4248
|
-
field,
|
|
4249
|
-
operator: 'GREATER_OR_EQUAL',
|
|
4250
|
-
data: new Date(value).toISOString(),
|
|
4251
|
-
});
|
|
4252
|
-
}
|
|
4253
|
-
if (externalFilter.defaultOperator === 'LESS_OR_EQUAL') {
|
|
4254
|
-
filters.push({
|
|
4255
|
-
field,
|
|
4256
|
-
operator: 'LESS_OR_EQUAL',
|
|
4257
|
-
data: new Date(value).toISOString(),
|
|
4258
|
-
});
|
|
4259
|
-
}
|
|
4260
|
-
}
|
|
4261
|
-
}
|
|
4262
|
-
}
|
|
4263
|
-
else {
|
|
4264
|
-
if (Array.isArray(value)) {
|
|
4265
|
-
if (value.length) {
|
|
4266
|
-
filters.push({
|
|
4267
|
-
field,
|
|
4268
|
-
operator: 'IN',
|
|
4269
|
-
data: value,
|
|
4270
|
-
});
|
|
4271
|
-
}
|
|
4272
|
-
}
|
|
4273
|
-
else if (typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
4274
|
-
if (value?.from) {
|
|
4275
|
-
filters.push({
|
|
4276
|
-
field,
|
|
4277
|
-
operator: 'GREATER_OR_EQUAL',
|
|
4278
|
-
data: DateUtilities.begin(value?.from).toISOString(),
|
|
4279
|
-
});
|
|
4280
|
-
}
|
|
4281
|
-
if (value?.to) {
|
|
4282
|
-
filters.push({
|
|
4283
|
-
field,
|
|
4284
|
-
operator: 'LESS_THAN',
|
|
4285
|
-
data: DateUtilities.begin(DateUtilities.addDays(value?.to, 1)).toISOString(),
|
|
4286
|
-
});
|
|
4287
|
-
}
|
|
4288
|
-
}
|
|
4289
|
-
else {
|
|
4290
|
-
filters.push({
|
|
4291
|
-
field,
|
|
4292
|
-
operator: externalFilter.defaultOperator || 'EQUAL',
|
|
4293
|
-
data: value,
|
|
4294
|
-
});
|
|
4295
|
-
}
|
|
4296
|
-
}
|
|
4297
|
-
}
|
|
4298
|
-
}
|
|
4299
|
-
for (const column of columns || []) {
|
|
4300
|
-
const { field } = column;
|
|
4301
|
-
const value = rawColumnFilter?.[field];
|
|
4302
|
-
const operator = columnOperator?.[field] || column.filter?.operator?.default;
|
|
4303
|
-
if (value !== undefined && value !== null && value !== '') {
|
|
4304
|
-
if (column.type === 'string') {
|
|
4305
|
-
// `operator` is the wide `Operator` union; in this data-bearing path it is a
|
|
4306
|
-
// single-value comparison operator, hence the cast to the `Filter` contract.
|
|
4307
|
-
filters.push({
|
|
4308
|
-
field: field,
|
|
4309
|
-
operator: operator || 'CONTAIN',
|
|
4310
|
-
data: value,
|
|
4311
|
-
});
|
|
4312
|
-
}
|
|
4313
|
-
else if (column.type === 'boolean') {
|
|
4314
|
-
filters.push({
|
|
4315
|
-
field: field,
|
|
4316
|
-
operator: 'EQUAL',
|
|
4317
|
-
data: value === true || value === 1 || value === 'true' || value === '1',
|
|
4318
|
-
});
|
|
4319
|
-
}
|
|
4320
|
-
else if (column.type === 'date' || column.type === 'datetime') {
|
|
4321
|
-
if (value && typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
4322
|
-
if (value?.from && value?.to) {
|
|
4323
|
-
filters.push({
|
|
4324
|
-
field: field,
|
|
4325
|
-
operator: 'BETWEEN',
|
|
4326
|
-
data: {
|
|
4327
|
-
from: DateUtilities.begin(value?.from).toISOString(),
|
|
4328
|
-
to: DateUtilities.end(value?.to).toISOString(),
|
|
4329
|
-
},
|
|
4330
|
-
});
|
|
4331
|
-
}
|
|
4332
|
-
else if (value?.from) {
|
|
4333
|
-
filters.push({
|
|
4334
|
-
field: field,
|
|
4335
|
-
operator: 'GREATER_OR_EQUAL',
|
|
4336
|
-
data: DateUtilities.begin(value?.from).toISOString(),
|
|
4337
|
-
});
|
|
4338
|
-
}
|
|
4339
|
-
else if (value?.to) {
|
|
4340
|
-
filters.push({
|
|
4341
|
-
field: field,
|
|
4342
|
-
operator: 'LESS_THAN',
|
|
4343
|
-
data: DateUtilities.begin(DateUtilities.addDays(value?.to, 1)).toISOString(),
|
|
4344
|
-
});
|
|
4345
|
-
}
|
|
4346
|
-
}
|
|
4347
|
-
else {
|
|
4348
|
-
if (DateUtilities.isDate(value)) {
|
|
4349
|
-
filters.push({
|
|
4350
|
-
field: field,
|
|
4351
|
-
operator: 'BETWEEN',
|
|
4352
|
-
data: {
|
|
4353
|
-
from: DateUtilities.begin(value).toISOString(),
|
|
4354
|
-
to: DateUtilities.end(value).toISOString(),
|
|
4355
|
-
},
|
|
4356
|
-
});
|
|
4357
|
-
}
|
|
4358
|
-
}
|
|
4359
|
-
}
|
|
4360
|
-
else {
|
|
4361
|
-
if (Array.isArray(value)) {
|
|
4362
|
-
if (value.length) {
|
|
4363
|
-
filters.push({
|
|
4364
|
-
field: field,
|
|
4365
|
-
operator: 'IN',
|
|
4366
|
-
data: value,
|
|
4367
|
-
});
|
|
4368
|
-
}
|
|
4369
|
-
}
|
|
4370
|
-
else {
|
|
4371
|
-
// `operator` is the wide `Operator` union; this data-bearing path uses a
|
|
4372
|
-
// single-value comparison operator, hence the cast to the `Filter` contract.
|
|
4373
|
-
filters.push({
|
|
4374
|
-
field: field,
|
|
4375
|
-
operator: operator || 'EQUAL',
|
|
4376
|
-
data: value,
|
|
4377
|
-
});
|
|
4378
|
-
}
|
|
4379
|
-
}
|
|
4380
|
-
}
|
|
4381
|
-
}
|
|
4382
|
-
if (orderBy && orderDirection) {
|
|
4383
|
-
orders.push({
|
|
4384
|
-
field: orderBy,
|
|
4385
|
-
direction: orderDirection,
|
|
4386
|
-
});
|
|
4387
|
-
}
|
|
4388
|
-
return req;
|
|
4389
|
-
};
|
|
4390
4529
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.25", ngImport: i0, type: SdTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4391
4530
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.25", type: SdTable, isStandalone: true, selector: "sd-table", inputs: { autoIdInput: { classPropertyName: "autoIdInput", publicName: "autoId", isSignal: true, isRequired: false, transformFunction: null }, option: { classPropertyName: "option", publicName: "option", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.data-autoid": "autoId()", "attr.data-loading": "loading() ? \"true\" : \"false\"" } }, providers: [
|
|
4392
4531
|
DatePipe,
|
|
@@ -4468,183 +4607,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.25", ngImpo
|
|
|
4468
4607
|
], template: "@let _configuration = configuration();\n@let _tableOption = tableOption()!;\n@let _loading = loading();\n@let _items = items();\n@let _total = total();\n@let _isFiltered = isFiltered();\n@let _requireFiltered = requireFiltered();\n@let _export = _tableOption?.export;\n@let _exporting = exporting();\n@let _titleDef = titleDef();\n@let _autoId = autoId();\n@let _exportTitle = exportTitle();\n@let _cellDef = cellDef();\n@let _footerDef = footerDef();\n@let _sdSubInformation = sdSubInformation();\n@let _configComponent = configComponent();\n@let _mobileFilter = mobileFilter();\n@let _selectedTableItems = selectedTableItems();\n<!-- why: tree kh\u00F4ng c\u00F2n c\u1ED9t ri\u00EAng \u2014 khi KH\u00D4NG c\u00F3 c\u1ED9t Index, icon expand nh\u00FAng v\u00E0o\n c\u1ED9t data \u0111\u1EA7u ti\u00EAn. \u0110\u00E2y l\u00E0 field c\u1EE7a c\u1ED9t \u0111\u00F3 (null n\u1EBFu c\u00F3 Index ho\u1EB7c kh\u00F4ng tree). -->\n@let _treeFirstField = _tableOption?.tree && !_tableOption.index?.enabled ? _configuration?.firstColumns?.[0]?.field : null;\n\n@if (_configuration) {\n @if (!_tableOption.filter?.disabled && !!_tableOption.filter?.externalFilters?.length && filterRegister) {\n <external-filter\n class=\"mb-16\"\n [autoId]=\"_autoId\"\n [filterRegister]=\"filterRegister\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\">\n </external-filter>\n }\n @let groupedItems = _items | sdTree: _tableOption.tree : treeRevision() | sdGroup: _tableOption : groupExpandState;\n\n <!-- Tree toggle d\u00F9ng chung: indent (theo c\u1EA5p) + slot chevron/spinner. Nh\u00FAng v\u00E0o\n c\u1ED9t Index ho\u1EB7c c\u1ED9t data \u0111\u1EA7u qua *ngTemplateOutlet (context: { row }). -->\n <ng-template #sdTreeToggle let-row=\"row\">\n @let _tree = row?.meta?.tree;\n @if (_tree) {\n <span class=\"sd-tree-indent\" [style.width.px]=\"(_tree.level ?? 0) * (_tableOption.tree?.indentSize ?? 20)\"></span>\n <span class=\"sd-tree-toggle-slot\">\n @if (_tree.hasChildren) {\n @if (_tree.isExpanding) {\n <span class=\"lds-ring sd-tree-spinner\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </span>\n } @else {\n @let _aid = _autoId;\n <button\n type=\"button\"\n class=\"sd-tree-toggle-btn\"\n [attr.data-autoid]=\"_aid ? _aid + '-tree-toggle-' + row.meta.id : null\"\n (click)=\"onTreeToggle(row); $event.stopPropagation()\">\n <mat-icon>{{ _tree.isExpanded ? 'expand_more' : 'chevron_right' }}</mat-icon>\n </button>\n }\n }\n </span>\n }\n </ng-template>\n\n <ng-content select=\"[sdTableTop]\"></ng-content>\n <div class=\"c-container\">\n @if (_loading) {\n <div class=\"c-loading\">\n <mat-spinner></mat-spinner>\n </div>\n }\n <div\n class=\"c-table\"\n sdScroll\n stickyShadow\n [style.max-height]=\"_tableOption.style?.maxHeight\"\n [style.min-height]=\"_tableOption.style?.minHeight\">\n <table\n mat-table\n [dataSource]=\"groupedItems\"\n [trackBy]=\"trackBy\"\n matSort\n [matSortDisabled]=\"!_tableOption.sort?.enable\"\n multiTemplateDataRows\n cdkDropList\n [cdkDropListData]=\"groupedItems\"\n [cdkDropListDisabled]=\"!_tableOption.rowReorder?.enabled\"\n [cdkDropListSortPredicate]=\"reorderSortPredicate\"\n (cdkDropListDropped)=\"onReorderDrop($event)\">\n @if (_tableOption.rowReorder?.enabled) {\n <ng-container matColumnDef=\"sdReorder\">\n <th mat-header-cell *matHeaderCellDef class=\"sd-reorder-header\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let row\" class=\"sd-reorder-cell\">\n @if (!row.meta?.group?.items?.length) {\n <mat-icon cdkDragHandle [class.sd-reorder-disabled]=\"isReorderDisabled(row)\">\n {{ _tableOption.rowReorder?.icon || 'drag_indicator' }}\n </mat-icon>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n }\n\n <ng-container matColumnDef=\"sdSubInformation\" sticky>\n <td class=\"p-0\" mat-cell *matCellDef=\"let item\" [attr.colspan]=\"_configuration.displayedColumns.length\">\n @if (_sdSubInformation?.templateRef) {\n @if (_tableOption.expand?.always) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n } @else {\n <div [@detailExpand]=\"item.isExpanded ? 'expanded' : 'collapsed'\">\n @if (item.isExpanded) {\n <ng-container *ngTemplateOutlet=\"_sdSubInformation?.templateRef!; context: { item: item }\"> </ng-container>\n }\n </div>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSubInformationAction\" stickyEnd>\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 1px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td mat-cell *matCellDef=\"let element\">\n @if (!element.isExpanding && !_tableOption.expand?.always) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-expand-' + element.meta.id : null\"\n type=\"link\"\n [prefixIcon]=\"element.isExpanded ? 'expand_less' : 'expand_more'\"\n (click)=\"onExpand(element)\"\n width=\"35px\">\n </sd-button>\n }\n @if (element.isExpanding) {\n <div class=\"lds-ring\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </div>\n }\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"sdSelection\" sticky>\n <th class=\"sd-selection-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n @let visibleSelectAll = _items | selectionVisibleSelectAll: _tableOption.selector | async;\n @if (visibleSelectAll) {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [ngModel]=\"isSelectAll()\"\n (ngModelChange)=\"isSelectAll.set($event)\"\n (change)=\"onSelectAll()\">\n </mat-checkbox>\n }\n </th>\n\n <td class=\"sd-selection-cell p-0\" mat-cell *matCellDef=\"let item\">\n @let visible = item | selectionVisible: _tableOption.selector;\n @if (visible) {\n @if (_tableOption.selector?.single) {\n <mat-radio-button\n class=\"c-selection px-8\"\n color=\"primary\"\n [checked]=\"item.meta.selector.isSelected\"\n (change)=\"item.meta.selector.isSelected = true; onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-radio-button>\n } @else {\n <mat-checkbox\n class=\"c-selection px-8\"\n color=\"primary\"\n [(ngModel)]=\"item.meta.selector.isSelected\"\n (change)=\"onSelect(item)\"\n [disabled]=\"_selectedTableItems | selectionDisabled: item : _tableOption.selector!\">\n </mat-checkbox>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @if (_tableOption.index?.enabled) {\n @let _pageOffset = pageOffset();\n @let _indexWidth = _tableOption.index?.width || '50px';\n <!-- why: khi tree, c\u1ED9t Index \"\u00F4m\" th\u00EAm chevron + indent. D\u00F9ng width:1px +\n nowrap (.sd-tree-index-cell) \u0111\u1EC3 c\u1ED9t co S\u00C1T n\u1ED9i dung, kh\u00F4ng chi\u1EBFm ch\u1ED7\n th\u1EEBa; header \"#\" canh tr\u00E1i l\u00F9i v\u00E0o (.sd-tree-index-header) cho th\u1EB3ng s\u1ED1. -->\n @let _treeIndex = !!_tableOption.tree;\n <ng-container matColumnDef=\"sdIndex\" sticky>\n <th\n [class.p-0]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n [class.sd-tree-index-header]=\"_treeIndex\"\n mat-header-cell\n *matHeaderCellDef\n [style.width]=\"_treeIndex ? '1px' : _indexWidth\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\">\n {{ _tableOption.index?.title || '#' }}\n </th>\n <td\n [class.px-4]=\"!_treeIndex\"\n [class.text-center]=\"!_treeIndex\"\n [class.sd-tree-index-cell]=\"_treeIndex\"\n mat-cell\n *matCellDef=\"let item; let i = dataIndex\"\n [style.width]=\"_treeIndex ? '1px' : null\"\n [style.min-width]=\"_treeIndex ? null : _indexWidth\"\n [style.max-width]=\"_treeIndex ? null : _indexWidth\">\n @if (!item?.meta?.group?.isGroupHeader) {\n @if (_treeIndex) {\n <!-- why: tree \u2192 chevron + indent + STT ph\u00E2n c\u1EA5p (1, 1.2, 1.2.1). T\u00F4 \u0111\u1EADm root (level 0). -->\n <span class=\"sd-tree-line\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n @if (item?.meta?.tree?.indexPath?.length) {\n <span class=\"sd-tree-stt\" [class.sd-stt-root]=\"(item.meta.tree.level ?? 0) === 0\">\n {{ item.meta.tree.indexPath.join('.') }}\n </span>\n }\n </span>\n } @else {\n {{ _pageOffset + i + 1 }}\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef [style.width]=\"_treeIndex ? '1px' : null\" [style.min-width]=\"_treeIndex ? null : _indexWidth\" [style.max-width]=\"_treeIndex ? null : _indexWidth\"></td>\n </ng-container>\n }\n <ng-container\n matColumnDef=\"sdCommand\"\n [sticky]=\"_tableOption.command?.align !== 'right'\"\n [stickyEnd]=\"_tableOption.command?.align === 'right'\">\n <th class=\"p-0\" mat-header-cell *matHeaderCellDef style=\"width: 50px\" [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"px-8\" mat-cell *matCellDef=\"let item\">\n <desktop-command\n [autoId]=\"_autoId\"\n [commands]=\"_tableOption.command?.commands || _tableOption.commands || []\"\n [item]=\"item\"\n [itemIndex]=\"groupedItems.indexOf(item)\"></desktop-command>\n </td>\n <td mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n <!-- why: group header row d\u00F9ng matRowDef RI\u00CANG v\u1EDBi column list ['sdGroupHeader']\n qua predicate when:isGroupHeaderRow. Cell colspan = displayedColumns.length \u0111\u1EC3\n span TO\u00C0N B\u1ED8 width data row. Tr\u00E1nh colspan trick overflow row khi c\u00E1c TD kh\u00E1c render. -->\n <ng-container matColumnDef=\"sdGroupHeader\">\n <td\n class=\"p-0 sd-group-header-cell\"\n mat-cell\n *matCellDef=\"let item\"\n [attr.colspan]=\"sdGroupColspan()\">\n <div class=\"sd-group-row d-flex align-items-center py-8\">\n <!-- why: slot 42px kh\u1EDBp width v\u1EDBi sd-selection-cell data row \u2192 checkbox group c\u0103n TR\u1EE4C d\u1ECDc \u0111\u00FAng v\u1EDBi checkbox data. -->\n @if (_tableOption.selector?.visible && !_tableOption.selector?.single) {\n <div class=\"sd-group-selection-slot d-flex align-items-center justify-content-center\">\n <mat-checkbox\n class=\"c-selection\"\n color=\"primary\"\n [checked]=\"isGroupAllSelected(item)\"\n [indeterminate]=\"isGroupIndeterminate(item)\"\n (change)=\"onSelectGroup(item, $event.checked)\">\n </mat-checkbox>\n </div>\n } @else {\n <div class=\"sd-group-selection-slot\"></div>\n }\n @if (_tableOption.group?.collapsible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-group-toggle-' + (item.meta.group?.key || item.meta.id) : null\"\n type=\"link\"\n [prefixIcon]=\"item.meta.group.isExpanded ? 'expand_more' : 'chevron_right'\"\n width=\"32px\"\n (click)=\"toggleGroupExpand(item)\">\n </sd-button>\n }\n @if (sdGroupDef()?.templateRef; as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl; context: groupContext(item)\"></ng-container>\n } @else {\n <span class=\"T14R\">{{ item.meta.group.values | json }}</span>\n }\n </div>\n </td>\n </ng-container>\n <!-- why: filler column \u1EDF cu\u1ED1i h\u1EA5p th\u1EE5 leftover space khi t\u1ED5ng width c\u00E1c c\u1ED9t data < container \u2014 gi\u1EEF cho selection/STT/command kh\u00F4ng b\u1ECB d\u00E3n. -->\n <ng-container matColumnDef=\"sdFiller\">\n <th class=\"sd-filler-cell p-0\" mat-header-cell *matHeaderCellDef [attr.rowspan]=\"_configuration.multipleHeader ? 2 : 1\"></th>\n <td class=\"sd-filler-cell p-0\" mat-cell *matCellDef=\"let item\"></td>\n <td class=\"sd-filler-cell p-0\" mat-footer-cell *matFooterCellDef></td>\n </ng-container>\n @for (column of _configuration.firstColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\" [sticky]=\"_configuration.fixedColumn[column.field]\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"px-8 py-8 c-th\"\n [sdColumnResize]=\"!!_tableOption.config?.resizable && column.type !== 'children'\"\n [minWidth]=\"column.minWidth\"\n [maxWidth]=\"column.maxWidth\"\n (resizeEnd)=\"onColumnResize(column.field, $event)\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\"\n [attr.rowspan]=\"_configuration.multipleHeader && column.type !== 'children' ? 2 : 1\"\n [attr.colspan]=\"column.type === 'children' ? column.children.length : 1\">\n <div>\n @if (column.type === 'children') {\n <div\n aria-hidden=\"true\"\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n } @else {\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @let hideInlineFilter =\n _tableOption.filter?.disabled ||\n _tableOption.filter?.hideInlineFilter === true ||\n (_tableOption.filter?.hideInlineFilter === 'auto' && !_isFiltered && _total! <= 10);\n @if (!hideInlineFilter) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n [class.d-none]=\"column.type === 'children'\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"(item.data && item.data[column.field]) || ''\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children' && !item?.meta?.group?.isGroupHeader) {\n @if (_treeFirstField && column.field === _treeFirstField) {\n <!-- why: kh\u00F4ng c\u00F3 c\u1ED9t Index \u2192 chevron + indent nh\u00FAng v\u00E0o c\u1ED9t data \u0111\u1EA7u (nh\u01B0 file explorer). -->\n <span class=\"sd-tree-line px-8\">\n <ng-container *ngTemplateOutlet=\"sdTreeToggle; context: { row: item }\"></ng-container>\n <desktop-cell class=\"d-block\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"></desktop-cell>\n </span>\n } @else {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n @for (column of _configuration.secondColumns; track column.field) {\n <ng-container [matColumnDef]=\"column.field\">\n <th\n mat-header-cell\n *matHeaderCellDef\n class=\"c-th px-8\"\n [style.width]=\"column.width\"\n [style.min-width]=\"column.minWidth || column.width\"\n [style.max-width]=\"column.maxWidth\">\n <div>\n <div\n aria-hidden=\"true\"\n mat-sort-header\n class=\"c-header-title\"\n [class.justify-content-end]=\"column.align === 'right'\"\n [class.text-right]=\"column.align === 'right'\"\n [disabled]=\"!column.sortable\">\n <column-title [column]=\"column\" [titleDef]=\"_titleDef[column.field]\"></column-title>\n </div>\n @if (!_tableOption.filter?.disabled && !_tableOption.filter?.hideInlineFilter && columnOperator) {\n <ng-container *sdDesktop>\n <column-filter\n [autoId]=\"_autoId\"\n [value]=\"columnFilter?.[column.field!]!\"\n [operator]=\"columnOperator[column.field]\"\n [columnFilter]=\"columnFilter!\"\n [cacheValues]=\"cacheValues\"\n [column]=\"column\"\n (operatorChange)=\"columnOperator[column.field] = $event!; onOperatorChange(column, $event)\"\n (filterChange)=\"onFilterChange()\"\n (filterCommit)=\"onFilterCommit()\">\n </column-filter>\n </ng-container>\n }\n </div>\n </th>\n <td\n class=\"c-td px-0\"\n mat-cell\n *matCellDef=\"let item\"\n [sdHoverCopy]=\"item[column.field]\"\n [sdHoverCopyDisabled]=\"!column.cell?.copiable\">\n @if (column.type !== 'children') {\n <desktop-cell class=\"d-block px-8\" [column]=\"column\" [item]=\"item\" [cellDef]=\"_cellDef\"> </desktop-cell>\n }\n </td>\n <td mat-footer-cell *matFooterCellDef>\n <ng-container *ngIf=\"_footerDef[column.field]\">\n <ng-container *ngTemplateOutlet=\"_footerDef[column.field].templateRef; context: { items: _items, column: column }\">\n </ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n <tr class=\"c-first-header\" mat-header-row *matHeaderRowDef=\"_configuration.firstHeaders; sticky: true\"></tr>\n @if (!!_configuration.secondHeaders.length) {\n <tr class=\"c-second-header\" mat-header-row *matHeaderRowDef=\"_configuration.secondHeaders; sticky: true\"></tr>\n }\n <!-- Group header row \u2014 ch\u1EC9 1 cell sdGroupHeader colspan to\u00E0n width. -->\n <tr\n mat-row\n *matRowDef=\"let row; columns: ['sdGroupHeader']; when: isGroupHeaderRow\"\n class=\"c-group-row-tr\"></tr>\n\n <!-- Data row \u2014 d\u00F9ng displayedColumns \u0111\u1EA7y \u0111\u1EE7; when isDataRow \u0111\u1EC3 lo\u1EA1i tr\u1EEB group header. -->\n <tr\n mat-row\n cdkDrag\n [cdkDragData]=\"row\"\n [cdkDragDisabled]=\"\n !_tableOption.rowReorder?.enabled ||\n !!row.meta?.group?.items?.length ||\n (row.meta?.tree?.level ?? 0) > 0 ||\n isReorderDisabled(row)\n \"\n *matRowDef=\"let row; columns: _configuration.displayedColumns; when: isDataRow\"\n matRipple\n class=\"c-row\"\n [class.sd-tree-row]=\"!!_tableOption.tree\"\n [ngClass]=\"_tableOption.tree ? 'sd-tree-level-' + (row.meta?.tree?.level ?? 0) : null\"\n [ngStyle]=\"rowStyle(row)\"\n [class.selected]=\"row.meta.selector.isSelected\"></tr>\n\n <!-- Sub-information row \u2014 also gated b\u1EDFi isDataRow \u0111\u1EC3 KH\u00D4NG render empty expand row d\u01B0\u1EDBi group header. -->\n <tr mat-row *matRowDef=\"let row; columns: ['sdSubInformation']; when: isDataRow\" class=\"c-detail-row\"></tr>\n @if (hasFooter() && !!_configuration.displayedFooters.length) {\n <tr mat-footer-row *matFooterRowDef=\"_configuration.displayedFooters; sticky: true\"></tr>\n }\n </table>\n @if (!_loading && !_total) {\n <div class=\"c-no-data-row\">\n @if (_isFiltered) {\n @if (tableConfiguration?.images?.filterEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterEmpty\" alt=\"filter-empty\" />\n } @else {\n <img class=\"c-image sd-image-filter-empty\" alt=\"filter-empty\" />\n }\n <div class=\"T16M\">{{ 'core.component.table.no-results' | translate }}</div>\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-results-hint' | translate }}</div>\n } @else {\n @if (_requireFiltered) {\n @if (tableConfiguration?.images?.filterRequired) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.filterRequired\" alt=\"filter-required\" />\n } @else {\n <img class=\"c-image sd-image-filter-required\" alt=\"filter-required\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.choose-filter-hint' | translate }}</div>\n } @else {\n @if (tableConfiguration?.images?.dataEmpty) {\n <img class=\"c-image\" [src]=\"tableConfiguration!.images!.dataEmpty\" alt=\"data-empty\" />\n } @else {\n <img class=\"c-image sd-image-data-empty\" alt=\"data-empty\" />\n }\n <div class=\"T16R text-secondary\">{{ 'core.component.table.no-data' | translate }}</div>\n }\n }\n </div>\n }\n </div>\n <div class=\"c-paginator\">\n <div class=\"c-action\">\n <ng-container *sdDesktop>\n @if (_tableOption.reload?.visible) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-reload' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.reload' | translate\"\n prefixIcon=\"refresh\"\n (click)=\"reload()\"\n [disabled]=\"!_items.length\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n @if (_export && _items.length) {\n @if (_export.type === 'custom') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCustom()\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible) {\n @if (_exporting) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [loading]=\"_exporting\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" type=\"link\"> </sd-button>\n } @else {\n @if (_export.visible === 'ALL' || !_export.visible) {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" [matMenuTriggerFor]=\"menu\" type=\"link\"> </sd-button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-excel' : null\" (click)=\"exportExcel()\" type=\"button\">\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\n <span> {{ 'core.component.table.export-excel' | translate }}</span>\n </button>\n <button mat-menu-item [attr.data-autoid]=\"_autoId ? _autoId + '-export-csv' : null\" (click)=\"exportCSV()\" type=\"button\">\n <mat-icon fontSet=\"material-icons-outlined\">file_download</mat-icon>\n <span> {{ 'core.component.table.export-csv' | translate }}</span>\n </button>\n </mat-menu>\n } @else if (_export.visible === 'EXCEL') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-excel' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportExcel()\" type=\"link\"> </sd-button>\n } @else if (_export.visible === 'CSV') {\n <sd-button [autoId]=\"_autoId ? _autoId + '-export-csv' : null\" class=\"mr-8\" [title]=\"_exportTitle\" prefixIcon=\"get_app\" (click)=\"exportCSV()\" type=\"link\"> </sd-button>\n }\n }\n }\n }\n }\n\n <ng-container *sdDesktop>\n @if (_configComponent) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-config' : null\"\n class=\"mr-8\"\n [title]=\"'core.component.table.setup-short' | translate\"\n prefixIcon=\"settings\"\n (click)=\"_configComponent.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n <!-- Mobile: n\u00FAt Filter m\u1EDF mobile-filter drawer (inline filter \u1EA9n tr\u00EAn mobile) -->\n <ng-container *sdMobile>\n @if (!_tableOption.filter?.disabled && _mobileFilter) {\n <sd-button\n [autoId]=\"_autoId ? _autoId + '-mobile-filter-open' : null\"\n class=\"mr-8\"\n prefixIcon=\"filter_alt\"\n (click)=\"_mobileFilter.open()\"\n type=\"link\">\n </sd-button>\n }\n </ng-container>\n </div>\n @let hidePaginator = !_tableOption.paginate?.pageSize || _total === undefined || _total <= _tableOption.paginate?.pageSize!;\n <!-- Desktop paginator: full config (pageSize dropdown, first/last buttons) -->\n <ng-container *sdDesktop>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [pageSizeOptions]=\"_tableOption.paginate?.pages!\"\n [showFirstLastButtons]=\"_tableOption.paginate?.showFirstLastButtons\"\n [hidePageSize]=\"_tableOption.paginate?.hidePageSize\"></mat-paginator>\n </ng-container>\n <!-- Mobile paginator: \u1EA9n pageSize dropdown + first/last buttons \u0111\u1EC3 ti\u1EBFt ki\u1EC7m kh\u00F4ng gian -->\n <ng-container *sdMobile>\n <mat-paginator\n [class.d-none]=\"_tableOption.paginate?.hidden || hidePaginator\"\n [length]=\"_total\"\n [pageSize]=\"_tableOption.paginate?.pageSize\"\n [showFirstLastButtons]=\"false\"\n hidePageSize></mat-paginator>\n </ng-container>\n <!-- \"\u0110ang hi\u1EC3n th\u1ECB...\" ch\u1EC9 desktop -->\n <ng-container *sdDesktop>\n @if (!_tableOption.paginate?.hidden && hidePaginator && _total !== undefined && _total > 0) {\n <div class=\"T14R pr-16\">\n {{ 'core.component.table.showing' | translate }} <span class=\"T14M ml-2\">1-{{ _total }}/{{ _total }}</span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <selector-action [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" [selectedTableItems]=\"_selectedTableItems\" (clear)=\"onClearSelection(groupedItems)\" />\n @if (_tableOption.config?.visible) {\n <config [autoId]=\"_autoId\" [tableOption]=\"_tableOption\" />\n }\n <!-- Mobile filter drawer \u2014 ch\u1EC9 instantiate khi c\u1EA7n render tr\u00EAn mobile -->\n @if (!_tableOption.filter?.disabled && filterRegister) {\n <mobile-filter\n [autoId]=\"_autoId\"\n [filter]=\"_tableOption.filter!\"\n [externalFilters]=\"_tableOption.filter?.externalFilters!\"\n [columns]=\"_configuration.firstColumns\"\n [filterDefs]=\"sdFilterDefs()\"\n [filterRegister]=\"filterRegister\"\n [cacheValues]=\"cacheValues\">\n </mobile-filter>\n }\n}\n", styles: [":host{display:flex;flex-direction:column;overflow:auto;width:100%;height:100%}:host .c-header-title{height:40px;display:flex;align-items:center}:host .c-container{position:relative;min-height:50px;display:flex;flex-direction:column;flex:1}:host .c-container .c-table{position:relative;flex:1;display:flex;flex-direction:column}:host .c-container .c-table table{border-collapse:separate;width:100%}:host .c-container .c-table table tr.c-first-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-second-header.mat-mdc-header-row{height:40px}:host .c-container .c-table table tr.c-detail-row{height:0}:host .c-container .c-table table tr.c-row.activated{background-color:#e5ecff}:host .c-container .c-table table tr.c-row.selected{background-color:#eef2ff}:host .c-container .c-table table tr.c-row:not(.selected):not(.activated):hover{background-color:#f5f5f5}:host .c-container .c-table table tr.c-row td{border-bottom-width:0}:host .c-container .c-table table tr.c-row.c-expandable{cursor:pointer}:host .c-container .c-table table tr.c-row.c-expandable:hover{background:#f5f5f5}:host .c-container .c-table table th.mat-mdc-header-cell{background-color:#f2f3f4;border-bottom:0!important}:host .c-container .c-table table td.mat-mdc-cell,:host .c-container .c-table table td.mat-mdc-footer-cell,:host .c-container .c-table table th.mat-mdc-header-cell{border-bottom-color:#f2f2f2!important}:host .c-container .c-table .c-th{vertical-align:middle;font-weight:500;font-size:14px;line-height:20px;color:#212121}:host .c-container .c-table .c-th.sd-col-resize-host{position:relative}:host .c-container .c-table .c-th.sd-resizing{-webkit-user-select:none;user-select:none}:host .c-container .c-table .c-th .sd-col-resize-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;-webkit-user-select:none;user-select:none;z-index:2}:host .c-container .c-table .c-th .sd-col-resize-handle:hover{background:#00000014}:host .c-container .c-table .c-td:first{padding-left:10px}:host .c-container .c-table .c-no-data-row{flex:1;width:100%;position:sticky;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .c-container .c-table .c-no-data-row .c-image{margin-bottom:16px;width:96px}:host .c-container .c-loading{position:absolute;inset:0 0 56px;background:#00000026;z-index:2;display:flex;align-items:center;justify-content:center}:host .c-container .c-paginator{display:flex;flex-direction:row;justify-content:space-between;align-items:center;background-color:#fff}:host .c-container .c-paginator .c-action{padding:5px}:host .c-container .c-empty{text-align:center;background-color:#fff;border:none!important}:host .c-container .c-empty mat-icon{font-size:150px;margin-top:30px;margin-bottom:30px;opacity:.2;width:auto;height:auto}:host button.c-btn-add{background-color:#fff;box-shadow:0 2px 4px #2f313629}:host .lds-ring{display:inline-block;position:relative;width:40px;height:40px}:host .lds-ring div{box-sizing:border-box;display:block;position:absolute;width:32px;height:32px;margin:4px;border:4px solid #cef;border-radius:50%;animation:lds-ring 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:#cef transparent transparent transparent}:host .lds-ring div:nth-child(1){animation-delay:-.45s}:host .lds-ring div:nth-child(2){animation-delay:-.3s}:host .lds-ring div:nth-child(3){animation-delay:-.15s}@keyframes lds-ring{0%{transform:rotate(0)}to{transform:rotate(360deg)}}:host .sd-reorder-header,:host .sd-reorder-cell{width:40px;min-width:40px;padding:0 4px;box-sizing:border-box}:host .sd-reorder-cell mat-icon{cursor:grab;color:#00000061;display:flex;align-items:center}:host .sd-reorder-cell mat-icon:active{cursor:grabbing}:host .sd-reorder-cell mat-icon.sd-reorder-disabled{opacity:.3;cursor:not-allowed;pointer-events:none}:host ::ng-deep .mat-sort-header-content{display:block;text-align:left;width:100%}:host ::ng-deep .mat-select-arrow{color:#a6a6a6}:host ::ng-deep .mat-sort-header-disabled{background-image:none!important;cursor:default!important;padding-right:0!important}:host ::ng-deep .mat-sort-header-container{align-items:start!important}:host ::ng-deep .mat-sort-header-arrow{margin-top:4px!important}:host ::ng-deep .mat-sort-header-arrow{display:none!important}:host ::ng-deep .mat-sort-header{cursor:pointer}:host ::ng-deep .mat-sort-header[aria-sort]{background-repeat:no-repeat;background-position:center right 0;background-size:16px 16px;cursor:pointer;padding-right:24px}:host ::ng-deep .mat-sort-header[aria-sort=none]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M12 5.83L15.17 9l1.41-1.41L12 3 7.41 7.59 8.83 9 12 5.83zm0 12.34L8.83 15l-1.41 1.41L12 21l4.59-4.59L15.17 15 12 18.17z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=ascending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z'/%3E%3C/svg%3E\")}:host ::ng-deep .mat-sort-header[aria-sort=descending]{background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24px' viewBox='0 0 24 24' width='24px' fill='%23000000'%3E%3Cpath d='M0 0h24v24H0V0z' fill='none'/%3E%3Cpath fill='%237A7A7A' d='M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z'/%3E%3C/svg%3E\")}:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--outlined .mat-mdc-form-field-infix,:host ::ng-deep .c-paginator .mat-mdc-paginator .mdc-text-field--no-label .mat-mdc-form-field-infix{padding-top:2px;padding-bottom:2px;min-height:32px}:host ::ng-deep .c-paginator .mat-mdc-paginator-range-label{margin:0 4px}:host ::ng-deep .c-paginator .mat-mdc-paginator-page-size-select mat-select{margin-top:2px!important}:host ::ng-deep .cdk-drag-preview{box-shadow:0 4px 12px #00000026;background:#fff;display:table;width:100%}:host ::ng-deep .cdk-drag-preview td{padding:0 8px;border-bottom:1px solid rgba(0,0,0,.12)}:host ::ng-deep .cdk-drag-placeholder{opacity:0}:host ::ng-deep .cdk-drop-list-dragging tr.c-row:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}:host ::ng-deep .sd-selection-cell{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .sd-filler-cell{width:auto;min-width:0;padding:0!important;border:0}:host ::ng-deep .sd-group-header-cell{background:#f5f7fc;border-top:1px solid #e6e9f2;border-bottom:1px solid #e6e9f2}:host ::ng-deep .sd-group-row{min-height:36px}:host ::ng-deep .sd-group-selection-slot{width:42px;min-width:42px;max-width:42px}:host ::ng-deep .c-selection{transform:scale(.85);transform-origin:center}:host ::ng-deep .sd-tree-line{display:inline-flex;align-items:center;min-height:32px}:host ::ng-deep .sd-tree-indent{flex:0 0 auto}:host ::ng-deep .sd-tree-toggle-slot{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px}:host ::ng-deep .sd-tree-toggle-btn{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:0;background:transparent;border-radius:50%;cursor:pointer;color:var(--sd-text-secondary, #5b6472);transition:background-color .15s ease}:host ::ng-deep .sd-tree-toggle-btn mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .sd-tree-toggle-btn:hover{background-color:#0f172a14}:host ::ng-deep .sd-tree-spinner{transform:scale(.45)}:host ::ng-deep .sd-tree-stt{margin-left:2px;white-space:nowrap}:host ::ng-deep .sd-tree-index-cell{text-align:left!important;white-space:nowrap;padding-left:8px;padding-right:8px}:host ::ng-deep .sd-tree-index-header{padding-left:32px}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0{background:#fbfcfe}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-0>td{font-weight:500}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-1{background:#fff}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-2{background:#fafbfd}:host ::ng-deep tr.c-row.sd-tree-row.sd-tree-level-3{background:#f6f8fb}:host ::ng-deep .sd-stt-root{font-weight:700;color:#1f2330}\n", ":host ::ng-deep .sticky-shadow-right{overflow:visible!important}:host ::ng-deep .sticky-shadow-right:after{content:\"\";position:absolute;top:0;right:0;bottom:0;width:8px;transform:translate(100%);background:linear-gradient(to right,rgba(0,0,0,.12),transparent);pointer-events:none}:host ::ng-deep .sticky-shadow-left{overflow:visible!important}:host ::ng-deep .sticky-shadow-left:after{content:\"\";position:absolute;top:0;left:0;bottom:0;width:8px;transform:translate(-100%);background:linear-gradient(to left,rgba(0,0,0,.12),transparent);pointer-events:none}\n"] }]
|
|
4469
4608
|
}], ctorParameters: () => [], propDecorators: { autoIdInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoId", required: false }] }], option: [{ type: i0.Input, args: [{ isSignal: true, alias: "option", required: true }] }], table: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatTable), { isSignal: true }] }], configComponent: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ConfigComponent), { isSignal: true }] }], sdPopupExport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SdPopupExport), { isSignal: true }] }], scroll: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SdScrollDirective), { isSignal: true }] }], quickAction: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SdQuickAction), { isSignal: true }] }], externalFilter: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ExternalFilterComponent), { isSignal: true }] }], mobileFilter: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MobileFilterComponent), { isSignal: true }] }], paginator: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatPaginator), { isSignal: true }] }], sort: [{ type: i0.ViewChild, args: [i0.forwardRef(() => MatSort), { isSignal: true }] }], sdSubInformation: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdTableExpandDefDirective), { isSignal: true }] }], sdGroupDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SdTableGroupDefDirective), { isSignal: true }] }], sdCellDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SdTableCellDefDirective), { isSignal: true }] }], sdFooterDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SdMaterialFooterDefDirective), { isSignal: true }] }], sdFilterDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SdTableFilterDefDirective), { isSignal: true }] }], sdTitleDefs: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SdTableTitleDefDirective), { isSignal: true }] }] } });
|
|
4470
4609
|
|
|
4471
|
-
const SdConvertToPagingReq = (filterRequest, args) => {
|
|
4472
|
-
const { externalFilters, columns, fieldMapping } = args;
|
|
4473
|
-
const req = {
|
|
4474
|
-
filters: [],
|
|
4475
|
-
orders: args?.orders || [],
|
|
4476
|
-
pageNumber: filterRequest.pageNumber,
|
|
4477
|
-
pageSize: filterRequest.pageSize,
|
|
4478
|
-
};
|
|
4479
|
-
const { filters } = req;
|
|
4480
|
-
const { rawExternalFilter, rawColumnFilter, columnOperator, orderBy, orderDirection } = filterRequest;
|
|
4481
|
-
// Xử lý external filter
|
|
4482
|
-
for (const externalFilter of externalFilters || []) {
|
|
4483
|
-
const value = rawExternalFilter?.[externalFilter.field];
|
|
4484
|
-
const field = fieldMapping?.[externalFilter.field] || externalFilter.field;
|
|
4485
|
-
// Nếu có giá trị thì mới xử lý filter
|
|
4486
|
-
if (value !== undefined && value !== null && value !== '') {
|
|
4487
|
-
if (externalFilter.type === 'string') {
|
|
4488
|
-
filters.push({
|
|
4489
|
-
field,
|
|
4490
|
-
operator: externalFilter.defaultOperator || 'CONTAIN',
|
|
4491
|
-
data: value,
|
|
4492
|
-
});
|
|
4493
|
-
}
|
|
4494
|
-
else if (externalFilter.type === 'boolean') {
|
|
4495
|
-
filters.push({
|
|
4496
|
-
field,
|
|
4497
|
-
operator: 'EQUAL',
|
|
4498
|
-
data: value === true || value === 1 || value === 'true' || value === '1',
|
|
4499
|
-
});
|
|
4500
|
-
}
|
|
4501
|
-
else if (externalFilter.type === 'date') {
|
|
4502
|
-
if (typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
4503
|
-
if (value?.from) {
|
|
4504
|
-
filters.push({
|
|
4505
|
-
field,
|
|
4506
|
-
operator: 'GREATER_OR_EQUAL',
|
|
4507
|
-
data: DateUtilities$1.begin(value?.from).toISOString(),
|
|
4508
|
-
});
|
|
4509
|
-
}
|
|
4510
|
-
if (value?.to) {
|
|
4511
|
-
filters.push({
|
|
4512
|
-
field,
|
|
4513
|
-
operator: 'LESS_THAN',
|
|
4514
|
-
data: DateUtilities$1.begin(DateUtilities$1.addDays(value?.to, 1)).toISOString(),
|
|
4515
|
-
});
|
|
4516
|
-
}
|
|
4517
|
-
}
|
|
4518
|
-
else {
|
|
4519
|
-
if (DateUtilities$1.isDate(value)) {
|
|
4520
|
-
if (externalFilter.defaultOperator === 'GREATER_OR_EQUAL') {
|
|
4521
|
-
filters.push({
|
|
4522
|
-
field,
|
|
4523
|
-
operator: 'GREATER_OR_EQUAL',
|
|
4524
|
-
data: DateUtilities$1.begin(value).toISOString(),
|
|
4525
|
-
});
|
|
4526
|
-
}
|
|
4527
|
-
if (externalFilter.defaultOperator === 'LESS_OR_EQUAL') {
|
|
4528
|
-
filters.push({
|
|
4529
|
-
field,
|
|
4530
|
-
operator: 'LESS_THAN',
|
|
4531
|
-
data: DateUtilities$1.begin(DateUtilities$1.addDays(value, 1)).toISOString(),
|
|
4532
|
-
});
|
|
4533
|
-
}
|
|
4534
|
-
}
|
|
4535
|
-
}
|
|
4536
|
-
}
|
|
4537
|
-
else {
|
|
4538
|
-
if (Array.isArray(value)) {
|
|
4539
|
-
if (value.length) {
|
|
4540
|
-
filters.push({
|
|
4541
|
-
field,
|
|
4542
|
-
operator: 'IN',
|
|
4543
|
-
data: value,
|
|
4544
|
-
});
|
|
4545
|
-
}
|
|
4546
|
-
}
|
|
4547
|
-
else {
|
|
4548
|
-
filters.push({
|
|
4549
|
-
field,
|
|
4550
|
-
operator: externalFilter.defaultOperator || 'EQUAL',
|
|
4551
|
-
data: value,
|
|
4552
|
-
});
|
|
4553
|
-
}
|
|
4554
|
-
}
|
|
4555
|
-
}
|
|
4556
|
-
}
|
|
4557
|
-
// Xử lý column filter
|
|
4558
|
-
for (const column of columns || []) {
|
|
4559
|
-
const value = rawColumnFilter?.[column.field];
|
|
4560
|
-
const field = fieldMapping?.[column.field] || column.field;
|
|
4561
|
-
const operator = columnOperator?.[column.field] || column.filter?.operator?.default;
|
|
4562
|
-
// Nếu có giá trị thì mới xử lý filter
|
|
4563
|
-
if (value !== undefined && value !== null && value !== '') {
|
|
4564
|
-
if (column.type === 'string') {
|
|
4565
|
-
filters.push({
|
|
4566
|
-
field,
|
|
4567
|
-
operator: operator || 'CONTAIN',
|
|
4568
|
-
data: value,
|
|
4569
|
-
});
|
|
4570
|
-
}
|
|
4571
|
-
else if (column.type === 'boolean') {
|
|
4572
|
-
filters.push({
|
|
4573
|
-
field,
|
|
4574
|
-
operator: 'EQUAL',
|
|
4575
|
-
data: value === true || value === 1 || value === 'true' || value === '1',
|
|
4576
|
-
});
|
|
4577
|
-
}
|
|
4578
|
-
else if (column.type === 'date' || column.type === 'datetime') {
|
|
4579
|
-
if (typeof value === 'object' && 'from' in value && 'to' in value) {
|
|
4580
|
-
if (value?.from && value?.to) {
|
|
4581
|
-
filters.push({
|
|
4582
|
-
field,
|
|
4583
|
-
operator: 'BETWEEN',
|
|
4584
|
-
data: {
|
|
4585
|
-
from: DateUtilities$1.begin(value?.from).toISOString(),
|
|
4586
|
-
to: DateUtilities$1.end(value?.to).toISOString(),
|
|
4587
|
-
},
|
|
4588
|
-
});
|
|
4589
|
-
}
|
|
4590
|
-
else if (value?.from) {
|
|
4591
|
-
filters.push({
|
|
4592
|
-
field,
|
|
4593
|
-
operator: 'GREATER_OR_EQUAL',
|
|
4594
|
-
data: DateUtilities$1.begin(value?.from).toISOString(),
|
|
4595
|
-
});
|
|
4596
|
-
}
|
|
4597
|
-
else if (value?.to) {
|
|
4598
|
-
filters.push({
|
|
4599
|
-
field,
|
|
4600
|
-
operator: 'LESS_THAN',
|
|
4601
|
-
data: DateUtilities$1.begin(DateUtilities$1.addDays(value?.to, 1)).toISOString(),
|
|
4602
|
-
});
|
|
4603
|
-
}
|
|
4604
|
-
}
|
|
4605
|
-
else {
|
|
4606
|
-
if (DateUtilities$1.isDate(value)) {
|
|
4607
|
-
filters.push({
|
|
4608
|
-
field,
|
|
4609
|
-
operator: 'BETWEEN',
|
|
4610
|
-
data: {
|
|
4611
|
-
from: DateUtilities$1.begin(value).toISOString(),
|
|
4612
|
-
to: DateUtilities$1.end(value).toISOString(),
|
|
4613
|
-
},
|
|
4614
|
-
});
|
|
4615
|
-
}
|
|
4616
|
-
}
|
|
4617
|
-
}
|
|
4618
|
-
else {
|
|
4619
|
-
if (Array.isArray(value)) {
|
|
4620
|
-
if (value.length) {
|
|
4621
|
-
filters.push({
|
|
4622
|
-
field,
|
|
4623
|
-
operator: 'IN',
|
|
4624
|
-
data: value,
|
|
4625
|
-
});
|
|
4626
|
-
}
|
|
4627
|
-
}
|
|
4628
|
-
else {
|
|
4629
|
-
filters.push({
|
|
4630
|
-
field,
|
|
4631
|
-
operator: operator || 'EQUAL',
|
|
4632
|
-
data: value,
|
|
4633
|
-
});
|
|
4634
|
-
}
|
|
4635
|
-
}
|
|
4636
|
-
}
|
|
4637
|
-
}
|
|
4638
|
-
// Xử lý orders
|
|
4639
|
-
if (orderBy && orderDirection) {
|
|
4640
|
-
req.orders.push({
|
|
4641
|
-
field: orderBy,
|
|
4642
|
-
direction: orderDirection,
|
|
4643
|
-
});
|
|
4644
|
-
}
|
|
4645
|
-
return req;
|
|
4646
|
-
};
|
|
4647
|
-
|
|
4648
4610
|
/**
|
|
4649
4611
|
* Generated bundle index. Do not edit.
|
|
4650
4612
|
*/
|