@servicemind.tis/angular-smart-data-table 1.0.0

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.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +278 -0
  3. package/fesm2022/servicemind.tis-angular-smart-data-table.mjs +3148 -0
  4. package/fesm2022/servicemind.tis-angular-smart-data-table.mjs.map +1 -0
  5. package/index.d.ts +5 -0
  6. package/lib/angular-smart-data-table.module.d.ts +38 -0
  7. package/lib/angular-smart-data-table.service.d.ts +6 -0
  8. package/lib/components/angular-columns-btn/angular-columns-btn.component.d.ts +39 -0
  9. package/lib/components/angular-smart-data-table/angular-smart-data-table.component.d.ts +205 -0
  10. package/lib/components/angular-smart-data-table-confirmation-dialog/angular-smart-data-table-confirmation-dialog.component.d.ts +10 -0
  11. package/lib/components/angular-smart-data-table-error-dialog/angular-smart-data-table-error-dialog.component.d.ts +10 -0
  12. package/lib/components/create-columns-template/create-columns-template.component.d.ts +42 -0
  13. package/lib/datasources/api.datasource.d.ts +18 -0
  14. package/lib/directives/scrolling/scrolling.directive.d.ts +11 -0
  15. package/lib/helpers/collection.helper.d.ts +92 -0
  16. package/lib/helpers/date-time.helper.d.ts +39 -0
  17. package/lib/helpers/filter-display.helper.d.ts +51 -0
  18. package/lib/helpers/query-params.helper.d.ts +47 -0
  19. package/lib/helpers/storage-helper.d.ts +3 -0
  20. package/lib/helpers/timeout-manager.helper.d.ts +72 -0
  21. package/lib/helpers/url.helper.d.ts +78 -0
  22. package/lib/helpers/validation.helper.d.ts +73 -0
  23. package/lib/interfaces/angular-selection-config.type.d.ts +16 -0
  24. package/lib/interfaces/data-not-found-config.type.d.ts +12 -0
  25. package/lib/interfaces/index.d.ts +4 -0
  26. package/lib/interfaces/smart-data-table-wrapper-columns-config.type.d.ts +38 -0
  27. package/lib/interfaces/url-config.type.d.ts +8 -0
  28. package/lib/pipes/angular-currency.pipe.d.ts +7 -0
  29. package/lib/pipes/angular-date-time-with-seconds.pipe.d.ts +7 -0
  30. package/lib/pipes/angular-date-time.pipe.d.ts +7 -0
  31. package/lib/pipes/angular-date.pipe.d.ts +7 -0
  32. package/lib/pipes/money.pipe.d.ts +9 -0
  33. package/lib/pipes/quantity.pipe.d.ts +9 -0
  34. package/lib/services/angular-helper.service.d.ts +17 -0
  35. package/lib/services/api.service.d.ts +11 -0
  36. package/lib/services/user-customization.service.d.ts +16 -0
  37. package/package.json +50 -0
  38. package/public-api.d.ts +4 -0
@@ -0,0 +1,3148 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, HostListener, Input, Directive, Inject, Component, EventEmitter, Output, Pipe, ViewChild, NgModule } from '@angular/core';
3
+ import { CdkColumnDef } from '@angular/cdk/table';
4
+ import * as i6 from '@angular/forms';
5
+ import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
6
+ import * as i3$1 from '@angular/router';
7
+ import { RouterLink, RouterOutlet } from '@angular/router';
8
+ import { BehaviorSubject, of, takeUntil, Subject, tap, map, shareReplay, debounceTime, distinctUntilChanged } from 'rxjs';
9
+ import { SelectionModel } from '@angular/cdk/collections';
10
+ import * as i13 from '@angular/cdk/drag-drop';
11
+ import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
12
+ import { catchError, finalize } from 'rxjs/operators';
13
+ import * as i1 from '@angular/common/http';
14
+ import * as i1$1 from '@angular/material/dialog';
15
+ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
16
+ import * as i12$1 from '@angular/material/paginator';
17
+ import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
18
+ import * as i15 from '@angular/material/sort';
19
+ import { MatSort, MatSortModule } from '@angular/material/sort';
20
+ import * as i13$1 from '@angular/material/table';
21
+ import { MatTable, MatTableModule } from '@angular/material/table';
22
+ import * as i5 from '@angular/cdk/layout';
23
+ import { Breakpoints, LayoutModule } from '@angular/cdk/layout';
24
+ import { DateTime } from 'luxon';
25
+ import * as i4 from '@angular/common';
26
+ import { CommonModule } from '@angular/common';
27
+ import * as i3 from '@angular/material/icon';
28
+ import { MatIconModule } from '@angular/material/icon';
29
+ import * as i8 from '@angular/material/form-field';
30
+ import { MatFormFieldModule } from '@angular/material/form-field';
31
+ import * as i10 from '@angular/material/input';
32
+ import { MatInputModule } from '@angular/material/input';
33
+ import * as i10$1 from '@angular/material/progress-spinner';
34
+ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
35
+ import * as i4$1 from '@angular/material/button';
36
+ import { MatButtonModule } from '@angular/material/button';
37
+ import * as i12 from '@angular/material/checkbox';
38
+ import { MatCheckboxModule } from '@angular/material/checkbox';
39
+ import * as i1$2 from '@angular/material/snack-bar';
40
+ import { MatSnackBarModule } from '@angular/material/snack-bar';
41
+ import * as i9 from '@angular/material/select';
42
+ import { MatSelectModule } from '@angular/material/select';
43
+ import * as i7 from '@angular/material/menu';
44
+ import { MatMenuModule } from '@angular/material/menu';
45
+ import * as i8$1 from '@angular/material/divider';
46
+ import { MatDividerModule } from '@angular/material/divider';
47
+ import { MatTooltipModule } from '@angular/material/tooltip';
48
+
49
+ class AngularSmartDataTableService {
50
+ constructor() { }
51
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
52
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableService, providedIn: 'root' });
53
+ }
54
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableService, decorators: [{
55
+ type: Injectable,
56
+ args: [{
57
+ providedIn: 'root'
58
+ }]
59
+ }], ctorParameters: () => [] });
60
+
61
+ class ApiDataSource {
62
+ apiService;
63
+ apiSubs;
64
+ apiSubject = new BehaviorSubject([]);
65
+ extraDataSubject = new BehaviorSubject(null);
66
+ loadingSubject = new BehaviorSubject(false);
67
+ loading$ = this.loadingSubject.asObservable();
68
+ totalDataLength = new BehaviorSubject(null);
69
+ totalDataLength$ = this.totalDataLength.asObservable();
70
+ constructor(apiService) {
71
+ this.apiService = apiService;
72
+ console.log(' DataSource Initialized...');
73
+ }
74
+ connect(collectionViewer) {
75
+ return this.apiSubject.asObservable();
76
+ }
77
+ disconnect(collectionViewer) {
78
+ this.apiSubject.complete();
79
+ this.extraDataSubject.complete();
80
+ this.loadingSubject.complete();
81
+ if (this.apiSubs) {
82
+ this.apiSubs.unsubscribe();
83
+ }
84
+ }
85
+ load(url, pageIndex, pageSize, search, filter, sortFilter) {
86
+ if (this.apiSubs) {
87
+ this.apiSubs.unsubscribe();
88
+ }
89
+ this.loadingSubject.next(true);
90
+ this.apiSubs = this.apiService.getList(url, (pageIndex + 1), pageSize, search, { filter }, { sortFilter }).pipe(catchError(() => of([])), finalize(() => this.loadingSubject.next(false))).subscribe(r => {
91
+ console.log(`DataSource: Url: ${url}, Reply:`, r);
92
+ // ✅ FIX: Ensure we always emit an array (even if empty) to prevent undefined issues
93
+ const data = r?.data || [];
94
+ const total = (Array.isArray(data) && data.length > 0) ? (r?.total || data.length) : 0;
95
+ this.totalDataLength.next(total);
96
+ this.apiSubject.next(data);
97
+ this.extraDataSubject.next(r?.extraData || null);
98
+ });
99
+ }
100
+ loadWithCancellation(url, pageIndex, pageSize, search, filter, sortFilter, cancelSubject) {
101
+ if (this.apiSubs) {
102
+ this.apiSubs.unsubscribe();
103
+ }
104
+ this.loadingSubject.next(true);
105
+ let apiCall$ = this.apiService.getList(url, (pageIndex + 1), pageSize, search, { filter }, { sortFilter }).pipe(catchError(() => of([])), finalize(() => this.loadingSubject.next(false)));
106
+ // Add cancellation capability if provided
107
+ if (cancelSubject) {
108
+ apiCall$ = apiCall$.pipe(takeUntil(cancelSubject));
109
+ }
110
+ this.apiSubs = apiCall$.subscribe(r => {
111
+ console.log(`DataSource: Url: ${url}, Reply:`, r);
112
+ // ✅ FIX: Ensure we always emit an array (even if empty) to prevent undefined issues
113
+ const data = r?.data || [];
114
+ const total = (Array.isArray(data) && data.length > 0) ? (r?.total || data.length) : 0;
115
+ this.totalDataLength.next(total);
116
+ this.apiSubject.next(data);
117
+ this.extraDataSubject.next(r?.extraData || null);
118
+ });
119
+ }
120
+ }
121
+
122
+ class ApiService {
123
+ http;
124
+ token = '';
125
+ constructor(http) {
126
+ this.http = http;
127
+ }
128
+ getList(apiUrl, currentPage = 1, limit = 10, search = '', filters, sortFilter) {
129
+ const body = { ...filters, ...sortFilter };
130
+ const encodedSearch = encodeURIComponent(search);
131
+ if (this.token) {
132
+ return this.http.post(`${apiUrl}?current_page=${currentPage}&per_page=${limit}&search=${encodedSearch}`, body, {
133
+ headers: {
134
+ 'Authorization': `Bearer ${this.token}`,
135
+ 'X-Brand-Id': '2'
136
+ }
137
+ });
138
+ }
139
+ return this.http.post(`${apiUrl}?current_page=${currentPage}&per_page=${limit}&search=${encodedSearch}`, body);
140
+ }
141
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: ApiService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
142
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: ApiService, providedIn: 'root' });
143
+ }
144
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: ApiService, decorators: [{
145
+ type: Injectable,
146
+ args: [{
147
+ providedIn: 'root'
148
+ }]
149
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
150
+
151
+ const setToLocalStorageWithExpiry = (key, value, ttl = 9 * 1000 * 60 * 60) => {
152
+ const now = new Date();
153
+ // `item` is an object which contains the original value
154
+ // as well as the time when it's supposed to expire
155
+ const item = {
156
+ value,
157
+ expiry: now.getTime() + ttl
158
+ };
159
+ localStorage.setItem(key, JSON.stringify(item));
160
+ };
161
+ const getFromLocalStorageWithExpiry = (key) => {
162
+ const itemStr = localStorage.getItem(key);
163
+ // if the item doesn't exist, return null
164
+ if (!itemStr) {
165
+ return null;
166
+ }
167
+ // Guard against corrupt / non-JSON values (e.g. written by an older version
168
+ // or other code). Treat an unparseable entry as missing and self-heal by
169
+ // removing it, instead of throwing and breaking the caller (ngOnChanges).
170
+ let item;
171
+ try {
172
+ item = JSON.parse(itemStr);
173
+ }
174
+ catch {
175
+ localStorage.removeItem(key);
176
+ return null;
177
+ }
178
+ const now = new Date();
179
+ if (!item.expiry) {
180
+ localStorage.removeItem(key);
181
+ return null;
182
+ }
183
+ // compare the expiry time of the item with the current time
184
+ if (now.getTime() > item.expiry) {
185
+ // If the item is expired, delete the item from storage
186
+ // and return null
187
+ localStorage.removeItem(key);
188
+ return null;
189
+ }
190
+ return item.value;
191
+ };
192
+ const removeMultipleKeys = (keys) => {
193
+ console.log('Storage Helper: Keys To Remove:', keys);
194
+ keys.forEach(key => {
195
+ localStorage.removeItem(key);
196
+ });
197
+ };
198
+
199
+ /**
200
+ * TimeoutManager - A utility class for managing timeouts to prevent memory leaks
201
+ *
202
+ * This class provides a centralized way to create, track, and clean up setTimeout calls.
203
+ * It automatically handles cleanup when component is destroyed to prevent memory leaks.
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * export class MyComponent implements OnDestroy {
208
+ * private timeoutManager = new TimeoutManager();
209
+ *
210
+ * someMethod() {
211
+ * this.timeoutManager.createTimeout(() => {
212
+ * console.log('Delayed execution');
213
+ * }, 1000);
214
+ * }
215
+ *
216
+ * ngOnDestroy() {
217
+ * this.timeoutManager.clearAll(); // Clean up all pending timeouts
218
+ * }
219
+ * }
220
+ * ```
221
+ */
222
+ class TimeoutManager {
223
+ activeTimeouts = new Set();
224
+ /**
225
+ * Creates a tracked timeout that will be automatically cleaned up
226
+ * @param callback - Function to execute after delay
227
+ * @param delay - Delay in milliseconds
228
+ * @returns The timeout ID (same as setTimeout return value)
229
+ */
230
+ createTimeout(callback, delay) {
231
+ const timeoutId = setTimeout(() => {
232
+ // Auto-remove from tracking when timeout executes naturally
233
+ this.activeTimeouts.delete(timeoutId);
234
+ callback();
235
+ }, delay);
236
+ // Add to tracking set
237
+ this.activeTimeouts.add(timeoutId);
238
+ return timeoutId;
239
+ }
240
+ /**
241
+ * Manually clear a specific timeout
242
+ * @param timeoutId - The timeout ID returned from createTimeout
243
+ */
244
+ clearTimeout(timeoutId) {
245
+ if (this.activeTimeouts.has(timeoutId)) {
246
+ clearTimeout(timeoutId);
247
+ this.activeTimeouts.delete(timeoutId);
248
+ }
249
+ }
250
+ /**
251
+ * Clear all pending timeouts
252
+ * This should be called in ngOnDestroy to prevent memory leaks
253
+ */
254
+ clearAll() {
255
+ this.activeTimeouts.forEach(timeoutId => clearTimeout(timeoutId));
256
+ this.activeTimeouts.clear();
257
+ }
258
+ /**
259
+ * Get the number of active (pending) timeouts
260
+ * Useful for debugging and testing
261
+ */
262
+ get activeCount() {
263
+ return this.activeTimeouts.size;
264
+ }
265
+ /**
266
+ * Check if a specific timeout is still active
267
+ * @param timeoutId - The timeout ID to check
268
+ */
269
+ isActive(timeoutId) {
270
+ return this.activeTimeouts.has(timeoutId);
271
+ }
272
+ }
273
+ /**
274
+ * Static helper functions for one-off timeout usage
275
+ * Use the TimeoutManager class for more comprehensive timeout management
276
+ */
277
+ class TimeoutHelper {
278
+ /**
279
+ * Create a single tracked timeout with external cleanup responsibility
280
+ * @param callback - Function to execute after delay
281
+ * @param delay - Delay in milliseconds
282
+ * @param trackingSet - Set to track the timeout for cleanup
283
+ * @returns The timeout ID
284
+ */
285
+ static createTrackedTimeout(callback, delay, trackingSet) {
286
+ const timeoutId = setTimeout(() => {
287
+ trackingSet.delete(timeoutId);
288
+ callback();
289
+ }, delay);
290
+ trackingSet.add(timeoutId);
291
+ return timeoutId;
292
+ }
293
+ /**
294
+ * Clear all timeouts in a tracking set
295
+ * @param trackingSet - Set containing timeout IDs to clear
296
+ */
297
+ static clearAllTimeouts(trackingSet) {
298
+ trackingSet.forEach(timeoutId => clearTimeout(timeoutId));
299
+ trackingSet.clear();
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Centralized date/time utility helper for consistent date handling across the library.
305
+ * Provides common date formatting and conversion functions to avoid code duplication.
306
+ */
307
+ class DateTimeHelper {
308
+ /**
309
+ * Formats a date value for display based on form control type
310
+ * @param value - The date value (Date, DateTime, string, number)
311
+ * @param formControlType - The type of form control ('date', 'date-time', etc.)
312
+ * @returns Formatted date string
313
+ */
314
+ static formatForDisplay(value, formControlType) {
315
+ if (!value)
316
+ return '';
317
+ const dateTime = this.toDateTime(value);
318
+ if (!dateTime?.isValid)
319
+ return '';
320
+ switch (formControlType) {
321
+ case 'date':
322
+ return dateTime.toFormat('dd-MM-yyyy');
323
+ case 'date-time':
324
+ return dateTime.toFormat('dd-MM-yyyy HH:mm');
325
+ case 'date-time-with-seconds':
326
+ return dateTime.toFormat('dd-MM-yyyy HH:mm:ss');
327
+ default:
328
+ return dateTime.toFormat('dd-MM-yyyy');
329
+ }
330
+ }
331
+ /**
332
+ * Converts various date formats to DateTime object
333
+ * @param value - Date value in various formats
334
+ * @returns DateTime object or null if invalid
335
+ */
336
+ static toDateTime(value) {
337
+ if (!value)
338
+ return null;
339
+ if (DateTime.isDateTime(value)) {
340
+ return value;
341
+ }
342
+ if (value instanceof Date) {
343
+ return DateTime.fromJSDate(value);
344
+ }
345
+ if (typeof value === 'string' && value !== '') {
346
+ // Try parsing as milliseconds first (if numeric string)
347
+ const numValue = Number(value);
348
+ if (!isNaN(numValue) && numValue > 0) {
349
+ return DateTime.fromMillis(numValue);
350
+ }
351
+ // Try parsing as ISO string
352
+ return DateTime.fromISO(value);
353
+ }
354
+ if (typeof value === 'number') {
355
+ return DateTime.fromMillis(value);
356
+ }
357
+ return null;
358
+ }
359
+ /**
360
+ * Converts date/DateTime objects to milliseconds for API calls
361
+ * @param value - Date value
362
+ * @returns Milliseconds or original value if not a date
363
+ */
364
+ static toMilliseconds(value) {
365
+ if (!value)
366
+ return value;
367
+ if (value instanceof Date) {
368
+ return DateTime.fromJSDate(value).toMillis();
369
+ }
370
+ if (DateTime.isDateTime(value)) {
371
+ return value.toMillis();
372
+ }
373
+ return value;
374
+ }
375
+ /**
376
+ * Checks if a query parameter key represents a date field
377
+ * @param key - Query parameter key
378
+ * @param value - Query parameter value
379
+ * @returns True if it's a date field
380
+ */
381
+ static isDateQueryParam(key, value) {
382
+ return key.toLowerCase().includes('date') && value.length === 13;
383
+ }
384
+ /**
385
+ * Parses date from query parameters
386
+ * @param value - Query parameter value (milliseconds as string)
387
+ * @returns DateTime object
388
+ */
389
+ static parseFromQueryParam(value) {
390
+ return DateTime.fromMillis(Number(value));
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Centralized query parameter utility helper for consistent URL parameter handling.
396
+ * Provides common functions for parsing, validating, and transforming query parameters.
397
+ */
398
+ class QueryParamsHelper {
399
+ /**
400
+ * Parses query parameters from URL and handles type conversions
401
+ * @param url - Full URL string
402
+ * @returns Parsed query parameters object
403
+ */
404
+ static parseQueryParams(url) {
405
+ const urlObj = new URL(url);
406
+ const params = new URLSearchParams(urlObj.search);
407
+ const paramsObj = {};
408
+ params.forEach((value, key) => {
409
+ // Check if the parameter already exists (for handling multiple values)
410
+ if (paramsObj.hasOwnProperty(key)) {
411
+ // If it's not already an array, convert it to an array
412
+ if (!Array.isArray(paramsObj[key])) {
413
+ paramsObj[key] = [paramsObj[key]];
414
+ }
415
+ // Push the new value to the existing array
416
+ paramsObj[key].push(value);
417
+ }
418
+ else {
419
+ // Assign the value to the key in the object
420
+ paramsObj[key] = value;
421
+ }
422
+ });
423
+ return paramsObj;
424
+ }
425
+ /**
426
+ * Checks if a query parameter value is valid (not empty, null, or undefined)
427
+ * @param value - Query parameter value
428
+ * @returns True if valid
429
+ */
430
+ static isValidParam(value) {
431
+ return value && value !== '' && value !== 'null' && value !== 'undefined';
432
+ }
433
+ /**
434
+ * Processes a query parameter value and handles arrays
435
+ * @param value - Raw query parameter value
436
+ * @returns Processed value (string or array)
437
+ */
438
+ static processParamValue(value) {
439
+ if (value.includes(',')) {
440
+ return value.split(',');
441
+ }
442
+ return value;
443
+ }
444
+ /**
445
+ * Processes query parameters for filter form with type conversions
446
+ * @param queryParams - Raw query parameters
447
+ * @param columnsCodeMapping - Column mapping for transformations
448
+ * @returns Processed filter and sort objects
449
+ */
450
+ static processForFilters(queryParams, columnsCodeMapping) {
451
+ const filterParams = {};
452
+ const sortParams = {};
453
+ let pageIndex = 0;
454
+ let pageSize = 10;
455
+ let search = '';
456
+ for (const key in queryParams) {
457
+ if (!this.isValidParam(queryParams[key]))
458
+ continue;
459
+ let fixedKeyMatched = false;
460
+ const value = queryParams[key];
461
+ // Handle fixed parameters
462
+ if (key.toLowerCase() === 'pageindex') {
463
+ // Guard against malformed/stale URLs (NaN, negative): fall back to 0.
464
+ const n = Number(value);
465
+ pageIndex = (isFinite(n) && n >= 0) ? n : 0;
466
+ fixedKeyMatched = true;
467
+ }
468
+ else if (key.toLowerCase() === 'pagesize') {
469
+ // Guard against malformed/stale URLs (NaN, zero, negative): fall back to 10.
470
+ const n = Number(value);
471
+ pageSize = (isFinite(n) && n > 0) ? n : 10;
472
+ fixedKeyMatched = true;
473
+ }
474
+ else if (key.toLowerCase() === 'sortby') {
475
+ sortParams.sortBy = value;
476
+ fixedKeyMatched = true;
477
+ }
478
+ else if (key.toLowerCase() === 'sortorder') {
479
+ sortParams.sortOrder = value;
480
+ fixedKeyMatched = true;
481
+ }
482
+ else if (key.toLowerCase() === 'search') {
483
+ search = value;
484
+ fixedKeyMatched = true;
485
+ }
486
+ else if (DateTimeHelper.isDateQueryParam(key, value)) {
487
+ // Handle date parameters
488
+ filterParams[key] = DateTimeHelper.parseFromQueryParam(value);
489
+ fixedKeyMatched = true;
490
+ }
491
+ if (!fixedKeyMatched) {
492
+ filterParams[key] = this.processParamValue(value);
493
+ // Apply transformation if mapping exists
494
+ const mapping = columnsCodeMapping.find(ccm => ccm.filterFormKey === key);
495
+ if (mapping?.transformQueryParamFn) {
496
+ filterParams[key] = mapping.transformQueryParamFn(filterParams[key]);
497
+ }
498
+ }
499
+ }
500
+ return { filterParams, sortParams, pageIndex, pageSize, search };
501
+ }
502
+ /**
503
+ * Builds query string from filter data with proper encoding
504
+ * @param filterData - Filter form data
505
+ * @param sortParams - Sort parameters
506
+ * @param pageIndex - Current page index
507
+ * @param pageSize - Current page size
508
+ * @param search - Search term
509
+ * @returns URLSearchParams object
510
+ */
511
+ static buildQueryString(filterData, sortParams, pageIndex, pageSize, search) {
512
+ const qs = new URLSearchParams();
513
+ // Process filter data
514
+ if (filterData) {
515
+ const processedFilter = { ...filterData };
516
+ // Convert date objects to milliseconds
517
+ for (const key in processedFilter) {
518
+ processedFilter[key] = DateTimeHelper.toMilliseconds(processedFilter[key]);
519
+ }
520
+ // Append filter parameters
521
+ Object.keys(processedFilter).forEach(key => {
522
+ const value = processedFilter[key];
523
+ if (this.isValidParam(value)) {
524
+ if (value === '*') {
525
+ qs.append(key, '');
526
+ }
527
+ else {
528
+ qs.append(key, value);
529
+ }
530
+ }
531
+ });
532
+ }
533
+ // Append sort parameters
534
+ if (sortParams) {
535
+ Object.keys(sortParams).forEach(key => {
536
+ if (this.isValidParam(sortParams[key])) {
537
+ qs.append(key, sortParams[key]);
538
+ }
539
+ });
540
+ }
541
+ // Append pagination and search
542
+ qs.append('pageIndex', pageIndex.toString());
543
+ qs.append('pageSize', pageSize.toString());
544
+ if (search !== '') {
545
+ qs.append('search', search);
546
+ }
547
+ return qs;
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Centralized filter display utility helper for managing filter value formatting and grouping.
553
+ * Handles the complex logic of grouping and displaying filter values in a consistent manner.
554
+ */
555
+ class FilterDisplayHelper {
556
+ /**
557
+ * Formats filter values based on form control type for display
558
+ * @param items - Array of filter display values
559
+ * @returns Processed array with formatted display values
560
+ */
561
+ static formatFilterValuesForDisplay(items) {
562
+ return items.map(item => {
563
+ const processedItem = { ...item };
564
+ // Handle different form control types
565
+ switch (item.formControlType) {
566
+ case 'input':
567
+ case 'checkbox':
568
+ // No special formatting needed
569
+ break;
570
+ case 'date':
571
+ processedItem.valueKey = DateTimeHelper.formatForDisplay(item.value, 'date');
572
+ break;
573
+ case 'date-time':
574
+ processedItem.valueKey = DateTimeHelper.formatForDisplay(item.value, 'date-time');
575
+ break;
576
+ default:
577
+ // Keep original valueKey if no special handling needed
578
+ break;
579
+ }
580
+ return processedItem;
581
+ });
582
+ }
583
+ /**
584
+ * Groups filter values by form control attributes
585
+ * @param data - Array of filter display values
586
+ * @returns Grouped filter values
587
+ */
588
+ static groupByFormControlAttributes(data) {
589
+ const groups = {};
590
+ // First format the data for display
591
+ const formattedData = this.formatFilterValuesForDisplay(data);
592
+ formattedData.forEach(item => {
593
+ const key = `${item.formControlName}-${item.formControlType}`;
594
+ if (!groups[key]) {
595
+ groups[key] = {
596
+ formControlName: item.formControlName,
597
+ formControlType: item.formControlType,
598
+ arrValues: []
599
+ };
600
+ }
601
+ const isSingleValue = this.isSingleValueFormControl(item.formControlType, item.isSingleValue);
602
+ // Check if only the last value should be kept due to isSingleValue or duplicated value/valueKey
603
+ if (isSingleValue) {
604
+ groups[key].arrValues = [item]; // Replace with the current item
605
+ }
606
+ else {
607
+ // Check for duplicate value and valueKey in the current array
608
+ const existingIndex = groups[key].arrValues.findIndex(x => x.value === item.value && x.valueKey === item.valueKey);
609
+ if (existingIndex !== -1) {
610
+ groups[key].arrValues[existingIndex] = item; // Replace the duplicate
611
+ }
612
+ else {
613
+ groups[key].arrValues.push(item); // Add new item
614
+ }
615
+ }
616
+ });
617
+ return Object.values(groups);
618
+ }
619
+ /**
620
+ * Determines if a form control should only have single values
621
+ * @param formControlType - Type of form control
622
+ * @param explicitSingleValue - Explicit single value flag
623
+ * @returns True if single value control
624
+ */
625
+ static isSingleValueFormControl(formControlType, explicitSingleValue) {
626
+ if (explicitSingleValue !== undefined) {
627
+ return explicitSingleValue;
628
+ }
629
+ return ['input', 'radio', 'date', 'date-time', 'toggle'].includes(formControlType);
630
+ }
631
+ /**
632
+ * Updates selected filter values by replacing values for a specific form control
633
+ * @param currentValues - Current selected filter values
634
+ * @param newValues - New values to add/update
635
+ * @param formControlName - Name of the form control being updated
636
+ * @returns Updated filter values and grouped values
637
+ */
638
+ static updateSelectedFilterValues(currentValues, newValues, formControlName) {
639
+ let targetFormControlName;
640
+ let newValuesArray;
641
+ if (Array.isArray(newValues)) {
642
+ newValuesArray = newValues;
643
+ targetFormControlName = formControlName || newValues[0]?.formControlName;
644
+ }
645
+ else {
646
+ newValuesArray = [newValues];
647
+ targetFormControlName = formControlName || newValues?.formControlName;
648
+ }
649
+ // Remove existing values for this form control
650
+ const filteredValues = currentValues.filter(sfv => sfv.formControlName !== targetFormControlName);
651
+ // Group the new values
652
+ const newGroupedValues = this.groupByFormControlAttributes(newValuesArray);
653
+ // Add new values for the target form control
654
+ newGroupedValues.forEach(gv => {
655
+ if (gv.formControlName === targetFormControlName) {
656
+ gv.arrValues.forEach(v => {
657
+ filteredValues.push(v);
658
+ });
659
+ }
660
+ });
661
+ // Return updated values and all grouped values
662
+ const allGroupedValues = this.groupByFormControlAttributes(filteredValues);
663
+ return {
664
+ selectedFilterValues: filteredValues,
665
+ selectedFilterGroupedValues: allGroupedValues
666
+ };
667
+ }
668
+ /**
669
+ * Filters selected values to only show those present in query parameters
670
+ * @param selectedValues - All selected filter values
671
+ * @param queryParams - Current query parameters
672
+ * @returns Filtered values for display
673
+ */
674
+ static getValuesForDisplay(selectedValues, queryParams) {
675
+ return selectedValues.filter(sf => queryParams.hasOwnProperty(sf.formControlName));
676
+ }
677
+ /**
678
+ * Removes a specific filter value from the collection
679
+ * @param selectedValues - Current selected filter values
680
+ * @param filterToRemove - Filter value to remove
681
+ * @returns Updated filter values
682
+ */
683
+ static removeFilterValue(selectedValues, filterToRemove) {
684
+ return selectedValues.filter(sfv => !(sfv.formControlName === filterToRemove.formControlName &&
685
+ sfv.valueKey === filterToRemove.valueKey));
686
+ }
687
+ }
688
+
689
+ /**
690
+ * Centralized validation utility helper for common validation tasks.
691
+ * Provides reusable validation functions to avoid code duplication.
692
+ */
693
+ class ValidationHelper {
694
+ /**
695
+ * Checks if a value is not null, undefined, or empty string
696
+ * @param value - Value to check
697
+ * @returns True if value has content
698
+ */
699
+ static hasValue(value) {
700
+ return value !== null && value !== undefined && value !== '';
701
+ }
702
+ /**
703
+ * Checks if any values in an object are non-empty
704
+ * @param obj - Object to check
705
+ * @returns True if any value is non-empty
706
+ */
707
+ static hasNonEmptyValue(obj) {
708
+ if (!obj)
709
+ return false;
710
+ return Object.values(obj).some(value => this.hasValue(value));
711
+ }
712
+ /**
713
+ * Checks if a form has any non-empty values
714
+ * @param formData - Form data object
715
+ * @returns True if form has any data
716
+ */
717
+ static hasFormData(formData) {
718
+ if (!formData)
719
+ return false;
720
+ return this.hasNonEmptyValue(formData);
721
+ }
722
+ /**
723
+ * Validates if an array has items
724
+ * @param array - Array to check
725
+ * @returns True if array exists and has items
726
+ */
727
+ static hasItems(array) {
728
+ return Array.isArray(array) && array.length > 0;
729
+ }
730
+ /**
731
+ * Checks if a URL is valid
732
+ * @param url - URL string to validate
733
+ * @returns True if URL is valid
734
+ */
735
+ static isValidUrl(url) {
736
+ if (!url || typeof url !== 'string')
737
+ return false;
738
+ try {
739
+ new URL(url);
740
+ return true;
741
+ }
742
+ catch {
743
+ return false;
744
+ }
745
+ }
746
+ /**
747
+ * Validates if a string is a valid number
748
+ * @param value - Value to check
749
+ * @returns True if value is a valid number
750
+ */
751
+ static isValidNumber(value) {
752
+ return !isNaN(Number(value)) && isFinite(Number(value));
753
+ }
754
+ /**
755
+ * Checks if an object has a specific property with a valid value
756
+ * @param obj - Object to check
757
+ * @param property - Property name
758
+ * @returns True if property exists and has a value
759
+ */
760
+ static hasProperty(obj, property) {
761
+ return obj && obj.hasOwnProperty(property) && this.hasValue(obj[property]);
762
+ }
763
+ /**
764
+ * Validates if a selection model row has the required key
765
+ * @param row - Row object
766
+ * @param keyName - Key property name
767
+ * @returns True if row has the key property with a value
768
+ */
769
+ static hasRowKey(row, keyName) {
770
+ return row && this.hasProperty(row, keyName);
771
+ }
772
+ /**
773
+ * Checks if a filter value should be processed (not null, empty, or invalid)
774
+ * @param value - Filter value
775
+ * @returns True if filter value is valid for processing
776
+ */
777
+ static isValidFilterValue(value) {
778
+ if (!this.hasValue(value))
779
+ return false;
780
+ // Check for common invalid filter values
781
+ const invalidValues = ['null', 'undefined', '*'];
782
+ if (typeof value === 'string' && invalidValues.includes(value)) {
783
+ return value === '*'; // Special case: '*' is valid but gets converted to empty string
784
+ }
785
+ return true;
786
+ }
787
+ /**
788
+ * Validates pagination parameters
789
+ * @param pageIndex - Page index
790
+ * @param pageSize - Page size
791
+ * @returns Object with validation results
792
+ */
793
+ static validatePagination(pageIndex, pageSize) {
794
+ const validPageIndex = this.isValidNumber(pageIndex) ? Number(pageIndex) : 0;
795
+ const validPageSize = this.isValidNumber(pageSize) ? Number(pageSize) : 10;
796
+ return {
797
+ isValid: validPageIndex >= 0 && validPageSize > 0,
798
+ pageIndex: Math.max(0, validPageIndex),
799
+ pageSize: Math.max(1, validPageSize)
800
+ };
801
+ }
802
+ }
803
+
804
+ /**
805
+ * Centralized collection management utility helper for common array and object operations.
806
+ * Provides reusable functions for managing collections, selections, and data structures.
807
+ */
808
+ class CollectionHelper {
809
+ /**
810
+ * Safely clears an array if it exists
811
+ * @param array - Array to clear
812
+ */
813
+ static clearArray(array) {
814
+ if (Array.isArray(array)) {
815
+ array.length = 0;
816
+ }
817
+ }
818
+ /**
819
+ * Safely clears a Set if it exists
820
+ * @param set - Set to clear
821
+ */
822
+ static clearSet(set) {
823
+ if (set instanceof Set) {
824
+ set.clear();
825
+ }
826
+ }
827
+ /**
828
+ * Safely clears a Map if it exists
829
+ * @param map - Map to clear
830
+ */
831
+ static clearMap(map) {
832
+ if (map instanceof Map) {
833
+ map.clear();
834
+ }
835
+ }
836
+ /**
837
+ * Gets a consistent identifier for a row based on available keys
838
+ * @param row - Row object
839
+ * @param primaryKey - Primary key property name (default: 'id')
840
+ * @param fallbackKey - Fallback key property name
841
+ * @returns Row identifier or JSON string as last resort
842
+ */
843
+ static getRowIdentifier(row, primaryKey = 'id', fallbackKey) {
844
+ if (!row)
845
+ return '';
846
+ // Try primary key first
847
+ if (row[primaryKey] !== undefined && row[primaryKey] !== null) {
848
+ return row[primaryKey];
849
+ }
850
+ // Try fallback key if provided
851
+ if (fallbackKey && row[fallbackKey] !== undefined && row[fallbackKey] !== null) {
852
+ return row[fallbackKey];
853
+ }
854
+ // Last resort: stringify the object (not recommended for large objects)
855
+ return JSON.stringify(row);
856
+ }
857
+ /**
858
+ * Creates a hash from an array of objects for cache validation
859
+ * @param items - Array of items to hash
860
+ * @param keyExtractor - Function to extract key from each item
861
+ * @returns Hash string
862
+ */
863
+ static createArrayHash(items, keyExtractor) {
864
+ if (!Array.isArray(items))
865
+ return '';
866
+ return JSON.stringify(items.map(keyExtractor));
867
+ }
868
+ /**
869
+ * Safely filters an array with predicate function
870
+ * @param array - Array to filter
871
+ * @param predicate - Filter predicate function
872
+ * @returns Filtered array or empty array if input is invalid
873
+ */
874
+ static safeFilter(array, predicate) {
875
+ if (!Array.isArray(array))
876
+ return [];
877
+ return array.filter(predicate);
878
+ }
879
+ /**
880
+ * Safely maps an array with transform function
881
+ * @param array - Array to map
882
+ * @param transform - Transform function
883
+ * @returns Mapped array or empty array if input is invalid
884
+ */
885
+ static safeMap(array, transform) {
886
+ if (!Array.isArray(array))
887
+ return [];
888
+ return array.map(transform);
889
+ }
890
+ /**
891
+ * Safely finds an item in array
892
+ * @param array - Array to search
893
+ * @param predicate - Find predicate function
894
+ * @returns Found item or undefined
895
+ */
896
+ static safeFind(array, predicate) {
897
+ if (!Array.isArray(array))
898
+ return undefined;
899
+ return array.find(predicate);
900
+ }
901
+ /**
902
+ * Creates a Map from an array for O(1) lookups
903
+ * @param array - Array to convert
904
+ * @param keyExtractor - Function to extract key from each item
905
+ * @returns Map with keys and items
906
+ */
907
+ static createLookupMap(array, keyExtractor) {
908
+ const map = new Map();
909
+ if (!Array.isArray(array))
910
+ return map;
911
+ array.forEach(item => {
912
+ const key = keyExtractor(item);
913
+ map.set(key, item);
914
+ });
915
+ return map;
916
+ }
917
+ /**
918
+ * Checks if two arrays have the same items (order doesn't matter)
919
+ * @param array1 - First array
920
+ * @param array2 - Second array
921
+ * @param keyExtractor - Function to extract comparison key
922
+ * @returns True if arrays contain same items
923
+ */
924
+ static arraysEqual(array1, array2, keyExtractor) {
925
+ if (!Array.isArray(array1) || !Array.isArray(array2))
926
+ return false;
927
+ if (array1.length !== array2.length)
928
+ return false;
929
+ if (keyExtractor) {
930
+ const keys1 = array1.map(keyExtractor).sort();
931
+ const keys2 = array2.map(keyExtractor).sort();
932
+ return JSON.stringify(keys1) === JSON.stringify(keys2);
933
+ }
934
+ else {
935
+ return JSON.stringify([...array1].sort()) === JSON.stringify([...array2].sort());
936
+ }
937
+ }
938
+ /**
939
+ * Safely removes items from a Set based on a predicate
940
+ * @param set - Set to modify
941
+ * @param predicate - Function to determine if item should be removed
942
+ */
943
+ static removeFromSet(set, predicate) {
944
+ if (!(set instanceof Set))
945
+ return;
946
+ const itemsToRemove = [];
947
+ set.forEach(item => {
948
+ if (predicate(item)) {
949
+ itemsToRemove.push(item);
950
+ }
951
+ });
952
+ itemsToRemove.forEach(item => set.delete(item));
953
+ }
954
+ /**
955
+ * Safely clones an array to prevent mutation issues
956
+ * @param array - Array to clone
957
+ * @returns Cloned array or empty array if input is invalid
958
+ */
959
+ static cloneArray(array) {
960
+ if (!Array.isArray(array))
961
+ return [];
962
+ return [...array];
963
+ }
964
+ /**
965
+ * Performs safe property access with default value
966
+ * @param obj - Object to access
967
+ * @param path - Property path (e.g., 'user.profile.name')
968
+ * @param defaultValue - Default value if property doesn't exist
969
+ * @returns Property value or default
970
+ */
971
+ static getNestedProperty(obj, path, defaultValue = null) {
972
+ if (!obj || !path)
973
+ return defaultValue;
974
+ // If there is no '.', just return the direct property
975
+ if (!path.includes('.')) {
976
+ return obj[path] !== undefined ? obj[path] : defaultValue;
977
+ }
978
+ // Otherwise, traverse the nested properties
979
+ try {
980
+ return path.split('.').reduce((acc, part) => {
981
+ return acc && acc[part] !== undefined ? acc[part] : defaultValue;
982
+ }, obj);
983
+ }
984
+ catch {
985
+ return defaultValue;
986
+ }
987
+ }
988
+ }
989
+
990
+ /**
991
+ * Centralized URL and navigation utility helper.
992
+ * Provides common functions for URL manipulation and navigation.
993
+ */
994
+ class UrlHelper {
995
+ /**
996
+ * Extracts the home URL from current window location
997
+ * @returns Home URL path
998
+ */
999
+ static getHomeUrl() {
1000
+ const pathname = window.location.pathname;
1001
+ return `/${pathname.split('/')[1]}`;
1002
+ }
1003
+ /**
1004
+ * Safely navigates to a URL if it's valid
1005
+ * @param router - Angular Router instance
1006
+ * @param url - URL to navigate to
1007
+ * @returns Promise<boolean> - Navigation result
1008
+ */
1009
+ static safeNavigate(router, url) {
1010
+ if (!url || typeof url !== 'string') {
1011
+ return null;
1012
+ }
1013
+ try {
1014
+ return router.navigateByUrl(url);
1015
+ }
1016
+ catch (error) {
1017
+ console.warn('Navigation error:', error);
1018
+ return null;
1019
+ }
1020
+ }
1021
+ /**
1022
+ * Updates the browser URL without navigation using Location service
1023
+ * @param location - Angular Location service
1024
+ * @param baseUrl - Base URL path
1025
+ * @param queryString - Query string parameters
1026
+ */
1027
+ static updateUrl(location, baseUrl, queryString) {
1028
+ const newUrl = `${baseUrl}?${queryString}`;
1029
+ const currentUrl = window.location.pathname + window.location.search;
1030
+ if (currentUrl !== newUrl) {
1031
+ location.go(newUrl);
1032
+ }
1033
+ }
1034
+ /**
1035
+ * Builds a complete URL with query parameters
1036
+ * @param baseUrl - Base URL path
1037
+ * @param queryParams - URLSearchParams object
1038
+ * @returns Complete URL string
1039
+ */
1040
+ static buildUrl(baseUrl, queryParams) {
1041
+ const queryString = queryParams.toString();
1042
+ return queryString ? `${baseUrl}?${queryString}` : baseUrl;
1043
+ }
1044
+ /**
1045
+ * Gets the base URL without query parameters
1046
+ * @param router - Angular Router instance
1047
+ * @returns Base URL string
1048
+ */
1049
+ static getBaseUrl(router) {
1050
+ return router.url.split('?')[0];
1051
+ }
1052
+ /**
1053
+ * Checks if current URL differs from generated URL
1054
+ * @param generatedUrl - Generated URL to compare
1055
+ * @returns True if URLs are different
1056
+ */
1057
+ static hasUrlChanged(generatedUrl) {
1058
+ const currentUrl = window.location.pathname + window.location.search;
1059
+ return currentUrl !== generatedUrl;
1060
+ }
1061
+ /**
1062
+ * Extracts query parameters from a URL string
1063
+ * @param url - Full URL string
1064
+ * @returns URLSearchParams object
1065
+ */
1066
+ static extractQueryParams(url) {
1067
+ try {
1068
+ const urlObj = new URL(url);
1069
+ return new URLSearchParams(urlObj.search);
1070
+ }
1071
+ catch (error) {
1072
+ console.warn('Invalid URL for query param extraction:', url);
1073
+ return null;
1074
+ }
1075
+ }
1076
+ /**
1077
+ * Handles button click actions (URL navigation or callback execution)
1078
+ * @param router - Angular Router instance
1079
+ * @param config - Button configuration object
1080
+ * @param primaryUrlKey - Primary URL property name (default: 'btnUrl')
1081
+ * @param primaryClickKey - Primary click handler property name (default: 'btnClick')
1082
+ */
1083
+ static handleButtonClick(router, config, primaryUrlKey = 'btnUrl', primaryClickKey = 'btnClick') {
1084
+ if (!config)
1085
+ return;
1086
+ // Try callback first
1087
+ if (config[primaryClickKey] && typeof config[primaryClickKey] === 'function') {
1088
+ try {
1089
+ config[primaryClickKey]();
1090
+ }
1091
+ catch (error) {
1092
+ console.warn('Error executing button callback:', error);
1093
+ }
1094
+ }
1095
+ // Fallback to URL navigation
1096
+ else if (config[primaryUrlKey]) {
1097
+ this.safeNavigate(router, config[primaryUrlKey]);
1098
+ }
1099
+ }
1100
+ /**
1101
+ * Handles secondary button click actions
1102
+ * @param router - Angular Router instance
1103
+ * @param config - Button configuration object
1104
+ */
1105
+ static handleSecondaryButtonClick(router, config) {
1106
+ this.handleButtonClick(router, config, 'secondBtnUrl', 'secondBtnClick');
1107
+ }
1108
+ /**
1109
+ * Validates if a URL string is properly formatted
1110
+ * @param url - URL to validate
1111
+ * @returns True if URL is valid
1112
+ */
1113
+ static isValidUrl(url) {
1114
+ if (!url || typeof url !== 'string')
1115
+ return false;
1116
+ try {
1117
+ // Allow relative URLs starting with '/'
1118
+ if (url.startsWith('/'))
1119
+ return true;
1120
+ // Validate absolute URLs
1121
+ new URL(url);
1122
+ return true;
1123
+ }
1124
+ catch {
1125
+ return false;
1126
+ }
1127
+ }
1128
+ /**
1129
+ * Safely encodes URL parameters
1130
+ * @param value - Value to encode
1131
+ * @returns Encoded string
1132
+ */
1133
+ static encodeParam(value) {
1134
+ if (value === null || value === undefined)
1135
+ return '';
1136
+ return encodeURIComponent(String(value));
1137
+ }
1138
+ }
1139
+
1140
+ class ScrollingDirective {
1141
+ el;
1142
+ constructor(el) {
1143
+ this.el = el;
1144
+ }
1145
+ angularSmartDataTableScrolling = false;
1146
+ // @HostListener('mouseenter') onMouseEnter() {}
1147
+ onMouseLeave() {
1148
+ // console.log("==== angularSmartDataTableScrolling mouseleave ===", this.el.nativeElement, this.angularSmartDataTableScrolling);
1149
+ this.el.nativeElement.classList.remove('more-scrollbar-width', 'more-scrollbar-height');
1150
+ }
1151
+ onMousemove(event) {
1152
+ // console.log("==== angularSmartDataTableScrolling mousemove clientX-clientY ===", event.clientX, event.clientY);
1153
+ // console.log("==== angularSmartDataTableScrolling mousemove clientWidth-clientHeight ===", this.el.nativeElement.clientWidth, this.el.nativeElement.clientHeight);
1154
+ // console.log("==== angularSmartDataTableScrolling mousemove offsetX-offsetY ===", this.el.nativeElement.offsetX, this.el.nativeElement.offsetY);
1155
+ // console.log("==== angularSmartDataTableScrolling mousemove offsetWidth-offsetLeft ===", this.el.nativeElement.offsetWidth, this.el.nativeElement.offsetLeft);
1156
+ // console.log("==== angularSmartDataTableScrolling mousemove json ===", {
1157
+ // clientX: event.clientX,
1158
+ // clientY: event.clientY,
1159
+ // clientWidth: this.el.nativeElement.clientWidth,
1160
+ // clientHeight: this.el.nativeElement.clientHeight,
1161
+ // offsetX: this.el.nativeElement.offsetX,
1162
+ // offsetY: this.el.nativeElement.offsetY,
1163
+ // offsetWidth: this.el.nativeElement.offsetWidth,
1164
+ // offsetLeft: this.el.nativeElement.offsetLeft,
1165
+ // rect: this.el.nativeElement.getBoundingClientRect()
1166
+ // });
1167
+ const rect = this.el.nativeElement.getBoundingClientRect();
1168
+ let xDistance = rect.left + this.el.nativeElement.clientWidth + 10 - event.clientX;
1169
+ // console.log("=== angularSmartDataTableScrolling mousemove xDistance ===", xDistance);
1170
+ xDistance < 15 && xDistance > -15 ? this.el.nativeElement.classList.add('more-scrollbar-width') : this.el.nativeElement.classList.remove('more-scrollbar-width');
1171
+ let yDistance = rect.top + this.el.nativeElement.clientHeight + 15 - event.clientY;
1172
+ // console.log("=== angularSmartDataTableScrolling mousemove yDistance ===", yDistance);
1173
+ yDistance < 20 && yDistance > -20 ? this.el.nativeElement.classList.add('more-scrollbar-height') : this.el.nativeElement.classList.remove('more-scrollbar-height');
1174
+ // this.el.nativeElement.classList.remove('more-scrollbar-width', 'more-scrollbar-height')
1175
+ }
1176
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: ScrollingDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
1177
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.7", type: ScrollingDirective, isStandalone: false, selector: "[angularSmartDataTableScrolling]", inputs: { angularSmartDataTableScrolling: "angularSmartDataTableScrolling" }, host: { listeners: { "mouseleave": "onMouseLeave()", "mousemove": "onMousemove($event)" } }, ngImport: i0 });
1178
+ }
1179
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: ScrollingDirective, decorators: [{
1180
+ type: Directive,
1181
+ args: [{
1182
+ selector: '[angularSmartDataTableScrolling]',
1183
+ standalone: false
1184
+ }]
1185
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { angularSmartDataTableScrolling: [{
1186
+ type: Input
1187
+ }], onMouseLeave: [{
1188
+ type: HostListener,
1189
+ args: ['mouseleave']
1190
+ }], onMousemove: [{
1191
+ type: HostListener,
1192
+ args: ['mousemove', ['$event']]
1193
+ }] } });
1194
+
1195
+ class UserCustomizationService {
1196
+ http;
1197
+ token = '';
1198
+ constructor(http) {
1199
+ this.http = http;
1200
+ }
1201
+ getColumnsTemplates(url, listComponent) {
1202
+ if (this.token) {
1203
+ return this.http.get(`${url}?listComponent=${listComponent}`, {
1204
+ headers: {
1205
+ 'Authorization': `Bearer ${this.token}`
1206
+ }
1207
+ });
1208
+ }
1209
+ return this.http.get(`${url}?listComponent=${listComponent}`);
1210
+ }
1211
+ addColumnsTemplate(url, body) {
1212
+ if (this.token) {
1213
+ return this.http.post(`${url}`, body, {
1214
+ headers: {
1215
+ 'Authorization': `Bearer ${this.token}`
1216
+ }
1217
+ });
1218
+ }
1219
+ return this.http.post(url, body);
1220
+ }
1221
+ updateColumnsTemplate(url, body) {
1222
+ if (this.token) {
1223
+ return this.http.post(`${url}`, body, {
1224
+ headers: {
1225
+ 'Authorization': `Bearer ${this.token}`
1226
+ }
1227
+ });
1228
+ }
1229
+ return this.http.post(url, body);
1230
+ }
1231
+ deleteColumnsTemplate(url, body) {
1232
+ if (this.token) {
1233
+ return this.http.put(`${url}`, body, {
1234
+ headers: {
1235
+ 'Authorization': `Bearer ${this.token}`
1236
+ }
1237
+ });
1238
+ }
1239
+ return this.http.put(url, body);
1240
+ }
1241
+ getSelectedColumnsTemplate(url, listComponent) {
1242
+ if (this.token) {
1243
+ return this.http.get(`${url}?listComponent=${listComponent}`, {
1244
+ headers: {
1245
+ 'Authorization': `Bearer ${this.token}`
1246
+ }
1247
+ });
1248
+ }
1249
+ return this.http.get(`${url}?listComponent=${listComponent}`);
1250
+ }
1251
+ updateSelectedColumnsTemplate(url, body) {
1252
+ if (this.token) {
1253
+ return this.http.post(`${url}`, body, {
1254
+ headers: {
1255
+ 'Authorization': `Bearer ${this.token}`
1256
+ }
1257
+ });
1258
+ }
1259
+ return this.http.post(url, body);
1260
+ }
1261
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: UserCustomizationService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
1262
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: UserCustomizationService, providedIn: 'root' });
1263
+ }
1264
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: UserCustomizationService, decorators: [{
1265
+ type: Injectable,
1266
+ args: [{
1267
+ providedIn: 'root'
1268
+ }]
1269
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
1270
+
1271
+ class AngularSmartDataTableErrorDialogComponent {
1272
+ dialogRef;
1273
+ data;
1274
+ constructor(dialogRef, data) {
1275
+ this.dialogRef = dialogRef;
1276
+ this.data = data;
1277
+ this.dialogRef.addPanelClass(['angular-smart-data-table-error-dialog']);
1278
+ }
1279
+ onClose() {
1280
+ this.dialogRef.close();
1281
+ }
1282
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableErrorDialogComponent, deps: [{ token: i1$1.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
1283
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.7", type: AngularSmartDataTableErrorDialogComponent, isStandalone: false, selector: "angular-smart-data-table-error-dialog", ngImport: i0, template: "<h1 mat-dialog-title>\n <mat-icon class=\"{{data?.iconClass}}\">{{data?.icon}}</mat-icon>\n {{data?.title}}\n</h1>\n<div mat-dialog-content>\n {{data?.message}}\n</div>\n<div mat-dialog-actions>\n <button mat-button class=\"angular-text-upper {{data?.buttonClass ?? 'angular-btn-primary'}}\" (click)=\"onClose()\" cdkFocusInitial *ngIf=\"data?.buttonText && data?.buttonText != ''\">{{data?.buttonText}}</button>\n</div>", styles: [""], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: i1$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }] });
1284
+ }
1285
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableErrorDialogComponent, decorators: [{
1286
+ type: Component,
1287
+ args: [{ selector: 'angular-smart-data-table-error-dialog', standalone: false, template: "<h1 mat-dialog-title>\n <mat-icon class=\"{{data?.iconClass}}\">{{data?.icon}}</mat-icon>\n {{data?.title}}\n</h1>\n<div mat-dialog-content>\n {{data?.message}}\n</div>\n<div mat-dialog-actions>\n <button mat-button class=\"angular-text-upper {{data?.buttonClass ?? 'angular-btn-primary'}}\" (click)=\"onClose()\" cdkFocusInitial *ngIf=\"data?.buttonText && data?.buttonText != ''\">{{data?.buttonText}}</button>\n</div>" }]
1288
+ }], ctorParameters: () => [{ type: i1$1.MatDialogRef }, { type: undefined, decorators: [{
1289
+ type: Inject,
1290
+ args: [MAT_DIALOG_DATA]
1291
+ }] }] });
1292
+
1293
+ class AngularHelperService {
1294
+ snackBar;
1295
+ dialog;
1296
+ http;
1297
+ constructor(snackBar, dialog, http) {
1298
+ this.snackBar = snackBar;
1299
+ this.dialog = dialog;
1300
+ this.http = http;
1301
+ }
1302
+ showHttpErrorMsg(error, duration = 5000) {
1303
+ console.log('httpError: ', error);
1304
+ let errorMessage = 'Some Unknown Error Occurred.';
1305
+ let errorCode = 'Unknown Error';
1306
+ const httpError = error;
1307
+ if (httpError.status >= 400) {
1308
+ const errorFromServer = httpError.error;
1309
+ if (Array.isArray(errorFromServer) && errorFromServer.length > 0) {
1310
+ errorMessage = errorFromServer[0].message;
1311
+ errorCode = errorFromServer[0].code;
1312
+ }
1313
+ }
1314
+ else if (httpError.status < 100) {
1315
+ errorMessage = httpError.message;
1316
+ errorCode = httpError.statusText;
1317
+ }
1318
+ if (errorCode == "VALIDATION_ERROR" || errorCode == "NOT_FOUND_ERROR" || errorCode == "THIRD_PARTY_API_ERROR") {
1319
+ let confirmBoxData = {
1320
+ title: "Error !",
1321
+ message: errorMessage,
1322
+ icon: "error",
1323
+ iconClass: "angular-text-danger",
1324
+ buttonText: "Ok",
1325
+ buttonClass: "angular-btn-primary",
1326
+ };
1327
+ const dialogRef = this.dialog.open(AngularSmartDataTableErrorDialogComponent, {
1328
+ width: "550px",
1329
+ panelClass: ['angular-simple-confirmation'],
1330
+ data: confirmBoxData,
1331
+ disableClose: false,
1332
+ });
1333
+ return dialogRef;
1334
+ }
1335
+ else {
1336
+ const snackbarRef = this.snackBar.open(errorMessage, 'Error', { duration: duration });
1337
+ return snackbarRef;
1338
+ }
1339
+ }
1340
+ showSuccessMsg(message, title, duration = 5000) {
1341
+ this.snackBar.open(message, title, {
1342
+ duration: duration
1343
+ });
1344
+ }
1345
+ showErrorMsg(message, title, duration = 5000) {
1346
+ this.snackBar.open(message, title, {
1347
+ duration: duration
1348
+ });
1349
+ }
1350
+ sortArrayByOrder(A, B) {
1351
+ const sortedA = [];
1352
+ for (const element of B) {
1353
+ const index = A.indexOf(element);
1354
+ if (index !== -1) {
1355
+ sortedA.push(A[index]);
1356
+ A.splice(index, 1);
1357
+ }
1358
+ }
1359
+ return [...sortedA, ...A]; // Combine sorted elements with remaining elements
1360
+ }
1361
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularHelperService, deps: [{ token: i1$2.MatSnackBar }, { token: i1$1.MatDialog }, { token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
1362
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularHelperService, providedIn: 'root' });
1363
+ }
1364
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularHelperService, decorators: [{
1365
+ type: Injectable,
1366
+ args: [{
1367
+ providedIn: 'root'
1368
+ }]
1369
+ }], ctorParameters: () => [{ type: i1$2.MatSnackBar }, { type: i1$1.MatDialog }, { type: i1.HttpClient }] });
1370
+
1371
+ class AngularSmartDataTableConfirmationDialogComponent {
1372
+ dialogRef;
1373
+ data;
1374
+ constructor(dialogRef, data) {
1375
+ this.dialogRef = dialogRef;
1376
+ this.data = data;
1377
+ this.dialogRef.addPanelClass(['angular-smart-data-table-confirmation-dialog']);
1378
+ }
1379
+ onClose(status) {
1380
+ this.dialogRef.close(status);
1381
+ }
1382
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableConfirmationDialogComponent, deps: [{ token: i1$1.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
1383
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: AngularSmartDataTableConfirmationDialogComponent, isStandalone: false, selector: "angular-smart-data-table-confirmation-dialog", ngImport: i0, template: "<h1 mat-dialog-title style=\"gap: 10px; justify-content: start; width: 100%; align-items: center; display: flex; padding: 8px 16px;\">\n <mat-icon class=\"{{data?.iconClass}}\" style=\"color: var(--angular-cancel, #bb333b)\">{{data?.icon}}</mat-icon>\n <span>{{data?.title}}</span>\n</h1>\n<div mat-dialog-content style=\"padding: 20px 24px; padding-top: 0px;\">\n @if(data?.html){\n <h5 class=\"title\">{{data?.message}}</h5>\n <div [innerHTML]=\"data.html\">\n </div>\n }\n @else {\n <span>{{data?.message}}</span>\n }\n</div>\n<div mat-dialog-actions style=\"border-top: 1px solid rgba(0, 0, 0, 0.12); justify-content: end;\">\n <button mat-button class=\"{{data?.cancelButtonClass}}\" style=\"color: var(--angular-primary, var(--mat-sys-primary))\" (click)=\"onClose(false)\" *ngIf=\"data?.cancelButtonText && data?.cancelButtonText != ''\">{{data?.cancelButtonText}}</button>\n <button mat-button class=\"{{data?.approveButtonClass}}\" style=\"color: var(--angular-cancel, #bb333b)\" (click)=\"onClose(true)\" cdkFocusInitial *ngIf=\"data?.approveButtonText && data?.approveButtonText != ''\">{{data?.approveButtonText}}</button>\n</div>", styles: [""], dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: i1$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }] });
1384
+ }
1385
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableConfirmationDialogComponent, decorators: [{
1386
+ type: Component,
1387
+ args: [{ selector: 'angular-smart-data-table-confirmation-dialog', standalone: false, template: "<h1 mat-dialog-title style=\"gap: 10px; justify-content: start; width: 100%; align-items: center; display: flex; padding: 8px 16px;\">\n <mat-icon class=\"{{data?.iconClass}}\" style=\"color: var(--angular-cancel, #bb333b)\">{{data?.icon}}</mat-icon>\n <span>{{data?.title}}</span>\n</h1>\n<div mat-dialog-content style=\"padding: 20px 24px; padding-top: 0px;\">\n @if(data?.html){\n <h5 class=\"title\">{{data?.message}}</h5>\n <div [innerHTML]=\"data.html\">\n </div>\n }\n @else {\n <span>{{data?.message}}</span>\n }\n</div>\n<div mat-dialog-actions style=\"border-top: 1px solid rgba(0, 0, 0, 0.12); justify-content: end;\">\n <button mat-button class=\"{{data?.cancelButtonClass}}\" style=\"color: var(--angular-primary, var(--mat-sys-primary))\" (click)=\"onClose(false)\" *ngIf=\"data?.cancelButtonText && data?.cancelButtonText != ''\">{{data?.cancelButtonText}}</button>\n <button mat-button class=\"{{data?.approveButtonClass}}\" style=\"color: var(--angular-cancel, #bb333b)\" (click)=\"onClose(true)\" cdkFocusInitial *ngIf=\"data?.approveButtonText && data?.approveButtonText != ''\">{{data?.approveButtonText}}</button>\n</div>" }]
1388
+ }], ctorParameters: () => [{ type: i1$1.MatDialogRef }, { type: undefined, decorators: [{
1389
+ type: Inject,
1390
+ args: [MAT_DIALOG_DATA]
1391
+ }] }] });
1392
+
1393
+ class CreateColumnsTemplateComponent {
1394
+ dialogRef;
1395
+ helper;
1396
+ snackBar;
1397
+ userCustomizationService;
1398
+ data;
1399
+ loading = false;
1400
+ updatingTemplate = false;
1401
+ savingTemplate = false;
1402
+ columns = [];
1403
+ displayedColumns = [];
1404
+ listComponentColumns;
1405
+ listComponentColumnsTemplateDetail;
1406
+ form;
1407
+ userId;
1408
+ translationReadKey;
1409
+ customColumns;
1410
+ t;
1411
+ columnCustomizationUrlConfig;
1412
+ constructor(dialogRef, helper, snackBar, userCustomizationService, data) {
1413
+ this.dialogRef = dialogRef;
1414
+ this.helper = helper;
1415
+ this.snackBar = snackBar;
1416
+ this.userCustomizationService = userCustomizationService;
1417
+ this.data = data;
1418
+ this.translationReadKey = this.data?.translationReadKey ?? '';
1419
+ if (this.data?.customColumns) {
1420
+ this.customColumns = this.data?.customColumns ?? {};
1421
+ }
1422
+ if (this.data?.columnCustomizationUrlConfig) {
1423
+ this.columnCustomizationUrlConfig = this.data.columnCustomizationUrlConfig;
1424
+ }
1425
+ this.dialogRef.addPanelClass(['angular-create-columns-template']);
1426
+ }
1427
+ ngOnInit() {
1428
+ this.t = this.data?.t || {};
1429
+ this.columns = JSON.parse(JSON.stringify(this.data.columns));
1430
+ this.displayedColumns = JSON.parse(JSON.stringify(this.data.displayColumns));
1431
+ this.displayedColumns = this.data.displayColumns;
1432
+ if (this.data?.defaultSelectedState == null || this.data?.defaultSelectedState == 'undefined') {
1433
+ this.data.defaultSelectedState = true;
1434
+ }
1435
+ if (this.data?.selectedTemplateId && this.displayedColumns?.length) {
1436
+ this.columns = this.helper.sortArrayByOrder(JSON.parse(JSON.stringify(this.columns)), JSON.parse(JSON.stringify(this.displayedColumns)));
1437
+ }
1438
+ this.listComponentColumns = this.columns.map((col, ndx) => ({ id: ndx + 1, isSelected: this.data?.defaultSelectedState === true ? true : (this.displayedColumns?.indexOf(col) >= 0 ? true : false), column: col }));
1439
+ this.createForm();
1440
+ // this.store.select('auth').subscribe((authState: fromAuth.State) => {
1441
+ // console.log('Current AuthState:', authState);
1442
+ // if(authState?.user?.id){
1443
+ // this.userId = authState.user.id;
1444
+ // }
1445
+ // })
1446
+ }
1447
+ ngAfterViewInit() {
1448
+ // this.translocoService.selectTranslate('lang', {}, 'shared').subscribe((translation: string) => {
1449
+ // this.tl = this.translocoService.translateObject('createColumnsTemplateComponent', {}, 'shared');
1450
+ // });
1451
+ }
1452
+ createForm() {
1453
+ this.form = new FormGroup({
1454
+ name: new FormControl(this.data?.name ?? '', Validators.required),
1455
+ enableStickiness: new FormControl(true),
1456
+ fromStartColumnNumber: new FormControl(this.data?.fromStartColumnNumber ? Number(this.data?.fromStartColumnNumber) : 0, Validators.required),
1457
+ fromEndColumnNumber: new FormControl(this.data?.fromEndColumnNumber ? Number(this.data?.fromEndColumnNumber) : 0, Validators.required),
1458
+ });
1459
+ }
1460
+ get name() {
1461
+ return this.form.get('name');
1462
+ }
1463
+ get listComponentColumnsTemplateName() {
1464
+ return this.name.value;
1465
+ }
1466
+ get orgDisplayColumns() {
1467
+ return this.displayedColumns;
1468
+ }
1469
+ drop(event) {
1470
+ moveItemInArray(this.listComponentColumns, event.previousIndex, event.currentIndex);
1471
+ }
1472
+ onSubmit() {
1473
+ const orgDisplayColumns = this.orgDisplayColumns;
1474
+ if (this.form.invalid) {
1475
+ return;
1476
+ }
1477
+ // Get selected columns (first filter on selected column and then get column array)
1478
+ this.displayedColumns = this.listComponentColumns.filter((r) => { if (r.isSelected)
1479
+ return r.column; }).map((r) => r.column);
1480
+ if (this.displayedColumns.length <= 0) {
1481
+ this.snackBar.open("Please select at least one column", "ok", {
1482
+ duration: 4000
1483
+ });
1484
+ return;
1485
+ }
1486
+ console.log('new and org display columns: ', this.displayedColumns, orgDisplayColumns);
1487
+ this.acceptTemplateNameAndSave();
1488
+ }
1489
+ acceptTemplateNameAndSave() {
1490
+ let data = {
1491
+ listComponentName: this.data.listComponentName,
1492
+ name: this.name.getRawValue(),
1493
+ enableStickiness: this.form.getRawValue().enableStickiness,
1494
+ fromStartColumnNumber: this.form.getRawValue().fromStartColumnNumber,
1495
+ fromEndColumnNumber: this.form.getRawValue().fromEndColumnNumber,
1496
+ defaultColumns: this.columns.join(),
1497
+ displayColumns: this.displayedColumns.join()
1498
+ };
1499
+ console.log('save value: ', data);
1500
+ this.savingTemplate = true;
1501
+ this.loading = true;
1502
+ if (this.data?.selectedTemplateId) {
1503
+ this.userCustomizationService.updateColumnsTemplate(this.columnCustomizationUrlConfig.update, { id: this.data?.selectedTemplateId, ...data }).subscribe(r => {
1504
+ console.log("add response: ", r);
1505
+ // this.loading = false;
1506
+ this.helper.showSuccessMsg(r.message, 'Success');
1507
+ let selectedTemplate = {
1508
+ ...r.data,
1509
+ ...data,
1510
+ isUpdated: true,
1511
+ };
1512
+ this.onClose(selectedTemplate);
1513
+ }, err => {
1514
+ this.loading = false;
1515
+ this.savingTemplate = false;
1516
+ this.helper.showHttpErrorMsg(err);
1517
+ });
1518
+ }
1519
+ else {
1520
+ this.userCustomizationService.addColumnsTemplate(this.columnCustomizationUrlConfig.add, data).subscribe(r => {
1521
+ console.log("add response: ", r);
1522
+ // this.loading = false;
1523
+ this.helper.showSuccessMsg(r.message, 'Success');
1524
+ let selectedTemplate = {
1525
+ ...r.data,
1526
+ ...data
1527
+ };
1528
+ this.onClose(selectedTemplate);
1529
+ }, err => {
1530
+ console.log(err);
1531
+ this.loading = false;
1532
+ this.savingTemplate = false;
1533
+ this.helper.showHttpErrorMsg(err);
1534
+ });
1535
+ }
1536
+ }
1537
+ onChangeColumnStatus(status, data) {
1538
+ if (status == false) {
1539
+ let leftColumn = data.id;
1540
+ let rightColumn = this.listComponentColumns?.length - (data.id - 1);
1541
+ let formValue = this.form.getRawValue();
1542
+ if (formValue?.fromStartColumnNumber == leftColumn) {
1543
+ this.form.patchValue({
1544
+ fromStartColumnNumber: 0
1545
+ });
1546
+ }
1547
+ if (formValue?.fromEndColumnNumber == rightColumn) {
1548
+ this.form.patchValue({
1549
+ fromEndColumnNumber: 0
1550
+ });
1551
+ }
1552
+ }
1553
+ }
1554
+ onClose(data = null) {
1555
+ this.dialogRef.close(data);
1556
+ }
1557
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: CreateColumnsTemplateComponent, deps: [{ token: i1$1.MatDialogRef }, { token: AngularHelperService }, { token: i1$2.MatSnackBar }, { token: UserCustomizationService }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
1558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: CreateColumnsTemplateComponent, isStandalone: false, selector: "angular-create-columns-template", ngImport: i0, template: "\n<form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <h1 mat-dialog-title style=\"padding: 16px 24px; background-color: #e0e0e0; display: flex; justify-content: space-between; width: 100%; align-items: center;\">\n {{t?.createColumnsTemplate?.title}}\n <mat-icon (click)=\"onClose()\" style=\"cursor: pointer;\">clear</mat-icon>\n </h1>\n <div style=\"padding: 15px; padding-bottom: 0px;\">\n <mat-form-field class=\"width-100 angular-mat-form-field\" appearance=\"outline\">\n <mat-label>{{t?.createColumnsTemplate?.templateName}}</mat-label>\n <input matInput formControlName=\"name\" placeholder=\"{{t?.createColumnsTemplate?.enterTemplateName}}\" />\n </mat-form-field>\n </div>\n\n <mat-dialog-content [angularSmartDataTableScrolling]=\"true\" class=\"w-100 p-0 m-0\" style=\"max-height: 60vh !important;\">\n <div cdkDropList class=\"example-list\" (cdkDropListDropped)=\"drop($event)\">\n <div class=\"example-box\" *ngFor=\"let item of listComponentColumns, let ndx = index\" cdkDrag>\n <div class=\"width-100 example-div\">\n <div class=\"example-item flex flex-row items-center\">\n <mat-icon cdkDragHandle style=\"cursor: pointer; color: rgba(0, 0, 0, 0.54); font-size: 19px; width: 19px; height: 19px;\">drag_indicator</mat-icon>\n <span *ngIf=\"!data?.skipTranslation\">{{t[item.column]}}</span>\n <span *ngIf=\"data?.skipTranslation\">{{customColumns[item.column]}}</span>\n </div>\n <mat-checkbox color=\"primary\" [(ngModel)]=\"item.isSelected\" (ngModelChange)=\"onChangeColumnStatus($event, item)\" [ngModelOptions]=\"{standalone: true}\"></mat-checkbox>\n </div>\n </div>\n </div>\n </mat-dialog-content>\n\n @if(form.value?.enableStickiness){\n <div style=\"padding: 15px; padding-bottom: 0px;\">\n <div style=\"display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem;\">\n <mat-form-field class=\"width-100 angular-mat-form-field\" appearance=\"outline\">\n <mat-label>{{t?.createColumnsTemplate?.freezeColumnFromLeft}}</mat-label>\n <mat-select formControlName=\"fromStartColumnNumber\">\n <mat-option [value]=\"0\">None</mat-option>\n @for (item of listComponentColumns; track item; let i = $index; let l = $last;) {\n @if(item?.isSelected){\n <mat-option [value]=\"(i+1)\">\n <span *ngIf=\"!data?.skipTranslation\">{{t[item.column]}}</span>\n <span *ngIf=\"data?.skipTranslation\">{{customColumns[item.column]}}</span>\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n <mat-form-field class=\"width-100 angular-mat-form-field\" appearance=\"outline\">\n <mat-label>{{t?.createColumnsTemplate?.freezeColumnFromRight}}</mat-label>\n <mat-select formControlName=\"fromEndColumnNumber\">\n <mat-option [value]=\"0\">None</mat-option>\n @for (item of listComponentColumns; track item; let i = $index; let l = $last;) {\n @if(item?.isSelected){\n <mat-option [value]=\"(listComponentColumns?.length - i)\">\n <span *ngIf=\"!data?.skipTranslation\">{{t[item.column]}}</span>\n <span *ngIf=\"data?.skipTranslation\">{{customColumns[item.column]}}</span>\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n }\n\n <div mat-dialog-actions>\n <button mat-button type=\"button\" class=\"angular-cancel-button\" mat-dialog-close [disabled]=\"loading\">{{t?.createColumnsTemplate?.cancel}}</button>\n <button mat-flat-button type=\"submit\" class=\"angular-submit-button\" cdkFocusInitial [disabled]=\"savingTemplate\">\n {{data?.selectedTemplateId ? t?.createColumnsTemplate?.update : t?.createColumnsTemplate?.save}}\n @if(savingTemplate){\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n </div>\n</form>", styles: [".width-100{width:100%!important}.example-container{width:400px;max-width:100%;margin:0 25px 25px 0;display:inline-block;vertical-align:top}.example-list{min-height:60px;background:#fff;border-radius:4px;overflow:hidden;display:block}.example-box{border-bottom:solid 1px #EEE;color:#000000de;display:flex;flex-direction:row;align-items:center;justify-content:space-between;box-sizing:border-box;background:#fff;font-size:14px}.example-div{display:flex;flex-direction:row;justify-content:space-between;align-items:center}.example-item{display:flex;flex-direction:row;align-items:center}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.mt-20{margin-top:20px}.mt-40{margin-top:40px}.w-10{width:10%}.w-100{width:100%}.container{width:100%;display:flex;align-items:center}.drag-index{font-size:16px;font-weight:500;padding:8px;width:40px;text-align:end}.drag-icon{background-color:#36834f;color:#fff;text-align:center;position:relative}.drag-icon i{padding-top:3px;cursor:move}.drag-content{margin-top:8px;padding-left:10px}.drag-content span{vertical-align:text-bottom;padding-left:5px}.angular-cancel-button:not(:disabled){text-transform:uppercase!important;color:var(--angular-primary, var(--mat-sys-primary, #3838a2))!important}.angular-cancel-button:not(:disabled):hover .mat-mdc-button-persistent-ripple:before{background-color:var(--angular-primary, var(--mat-sys-primary, #3838a2))}.angular-submit-button:not(:disabled){text-transform:uppercase!important;color:#fff!important;background-color:var(--angular-primary, var(--mat-sys-primary, #3838a2))!important}\n"], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i6.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i6.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i6.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatLabel, selector: "mat-label" }, { kind: "component", type: i9.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i10.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: i1$1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: i12.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: i13.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i13.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i13.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: ScrollingDirective, selector: "[angularSmartDataTableScrolling]", inputs: ["angularSmartDataTableScrolling"] }] });
1559
+ }
1560
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: CreateColumnsTemplateComponent, decorators: [{
1561
+ type: Component,
1562
+ args: [{ selector: 'angular-create-columns-template', standalone: false, template: "\n<form [formGroup]=\"form\" (ngSubmit)=\"onSubmit()\">\n <h1 mat-dialog-title style=\"padding: 16px 24px; background-color: #e0e0e0; display: flex; justify-content: space-between; width: 100%; align-items: center;\">\n {{t?.createColumnsTemplate?.title}}\n <mat-icon (click)=\"onClose()\" style=\"cursor: pointer;\">clear</mat-icon>\n </h1>\n <div style=\"padding: 15px; padding-bottom: 0px;\">\n <mat-form-field class=\"width-100 angular-mat-form-field\" appearance=\"outline\">\n <mat-label>{{t?.createColumnsTemplate?.templateName}}</mat-label>\n <input matInput formControlName=\"name\" placeholder=\"{{t?.createColumnsTemplate?.enterTemplateName}}\" />\n </mat-form-field>\n </div>\n\n <mat-dialog-content [angularSmartDataTableScrolling]=\"true\" class=\"w-100 p-0 m-0\" style=\"max-height: 60vh !important;\">\n <div cdkDropList class=\"example-list\" (cdkDropListDropped)=\"drop($event)\">\n <div class=\"example-box\" *ngFor=\"let item of listComponentColumns, let ndx = index\" cdkDrag>\n <div class=\"width-100 example-div\">\n <div class=\"example-item flex flex-row items-center\">\n <mat-icon cdkDragHandle style=\"cursor: pointer; color: rgba(0, 0, 0, 0.54); font-size: 19px; width: 19px; height: 19px;\">drag_indicator</mat-icon>\n <span *ngIf=\"!data?.skipTranslation\">{{t[item.column]}}</span>\n <span *ngIf=\"data?.skipTranslation\">{{customColumns[item.column]}}</span>\n </div>\n <mat-checkbox color=\"primary\" [(ngModel)]=\"item.isSelected\" (ngModelChange)=\"onChangeColumnStatus($event, item)\" [ngModelOptions]=\"{standalone: true}\"></mat-checkbox>\n </div>\n </div>\n </div>\n </mat-dialog-content>\n\n @if(form.value?.enableStickiness){\n <div style=\"padding: 15px; padding-bottom: 0px;\">\n <div style=\"display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem;\">\n <mat-form-field class=\"width-100 angular-mat-form-field\" appearance=\"outline\">\n <mat-label>{{t?.createColumnsTemplate?.freezeColumnFromLeft}}</mat-label>\n <mat-select formControlName=\"fromStartColumnNumber\">\n <mat-option [value]=\"0\">None</mat-option>\n @for (item of listComponentColumns; track item; let i = $index; let l = $last;) {\n @if(item?.isSelected){\n <mat-option [value]=\"(i+1)\">\n <span *ngIf=\"!data?.skipTranslation\">{{t[item.column]}}</span>\n <span *ngIf=\"data?.skipTranslation\">{{customColumns[item.column]}}</span>\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n <mat-form-field class=\"width-100 angular-mat-form-field\" appearance=\"outline\">\n <mat-label>{{t?.createColumnsTemplate?.freezeColumnFromRight}}</mat-label>\n <mat-select formControlName=\"fromEndColumnNumber\">\n <mat-option [value]=\"0\">None</mat-option>\n @for (item of listComponentColumns; track item; let i = $index; let l = $last;) {\n @if(item?.isSelected){\n <mat-option [value]=\"(listComponentColumns?.length - i)\">\n <span *ngIf=\"!data?.skipTranslation\">{{t[item.column]}}</span>\n <span *ngIf=\"data?.skipTranslation\">{{customColumns[item.column]}}</span>\n </mat-option>\n }\n }\n </mat-select>\n </mat-form-field>\n </div>\n </div>\n }\n\n <div mat-dialog-actions>\n <button mat-button type=\"button\" class=\"angular-cancel-button\" mat-dialog-close [disabled]=\"loading\">{{t?.createColumnsTemplate?.cancel}}</button>\n <button mat-flat-button type=\"submit\" class=\"angular-submit-button\" cdkFocusInitial [disabled]=\"savingTemplate\">\n {{data?.selectedTemplateId ? t?.createColumnsTemplate?.update : t?.createColumnsTemplate?.save}}\n @if(savingTemplate){\n <i class=\"fas fa-spinner fa-spin\"></i>\n }\n </button>\n </div>\n</form>", styles: [".width-100{width:100%!important}.example-container{width:400px;max-width:100%;margin:0 25px 25px 0;display:inline-block;vertical-align:top}.example-list{min-height:60px;background:#fff;border-radius:4px;overflow:hidden;display:block}.example-box{border-bottom:solid 1px #EEE;color:#000000de;display:flex;flex-direction:row;align-items:center;justify-content:space-between;box-sizing:border-box;background:#fff;font-size:14px}.example-div{display:flex;flex-direction:row;justify-content:space-between;align-items:center}.example-item{display:flex;flex-direction:row;align-items:center}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.mt-20{margin-top:20px}.mt-40{margin-top:40px}.w-10{width:10%}.w-100{width:100%}.container{width:100%;display:flex;align-items:center}.drag-index{font-size:16px;font-weight:500;padding:8px;width:40px;text-align:end}.drag-icon{background-color:#36834f;color:#fff;text-align:center;position:relative}.drag-icon i{padding-top:3px;cursor:move}.drag-content{margin-top:8px;padding-left:10px}.drag-content span{vertical-align:text-bottom;padding-left:5px}.angular-cancel-button:not(:disabled){text-transform:uppercase!important;color:var(--angular-primary, var(--mat-sys-primary, #3838a2))!important}.angular-cancel-button:not(:disabled):hover .mat-mdc-button-persistent-ripple:before{background-color:var(--angular-primary, var(--mat-sys-primary, #3838a2))}.angular-submit-button:not(:disabled){text-transform:uppercase!important;color:#fff!important;background-color:var(--angular-primary, var(--mat-sys-primary, #3838a2))!important}\n"] }]
1563
+ }], ctorParameters: () => [{ type: i1$1.MatDialogRef }, { type: AngularHelperService }, { type: i1$2.MatSnackBar }, { type: UserCustomizationService }, { type: undefined, decorators: [{
1564
+ type: Inject,
1565
+ args: [MAT_DIALOG_DATA]
1566
+ }] }] });
1567
+
1568
+ class AngularColumnsBtnComponent {
1569
+ helper;
1570
+ userCustomizationService;
1571
+ dialog;
1572
+ static COMPONENT_NAME = 'AngularColumnsBtnComponent';
1573
+ columnCustomizationUrlConfig;
1574
+ t = {};
1575
+ componentName;
1576
+ defaultColumns;
1577
+ columns;
1578
+ skipTranslation = false;
1579
+ customColumns;
1580
+ selectedTemplate = {
1581
+ id: -1,
1582
+ name: 'Default',
1583
+ fromStartColumnNumber: 0,
1584
+ fromEndColumnNumber: 0,
1585
+ };
1586
+ selectedTemplateChange = new EventEmitter();
1587
+ displayedColumnsChange = new EventEmitter();
1588
+ fromStartColumnNumberChange = new EventEmitter();
1589
+ fromEndColumnNumberChange = new EventEmitter();
1590
+ displayedColumns = [];
1591
+ templates = [];
1592
+ isDeleteTemplate = false;
1593
+ isEditTemplate = false;
1594
+ constructor(helper, userCustomizationService, dialog) {
1595
+ this.helper = helper;
1596
+ this.userCustomizationService = userCustomizationService;
1597
+ this.dialog = dialog;
1598
+ }
1599
+ ngOnInit() {
1600
+ this.getColumnsTemplates();
1601
+ // setTimeout(() => {
1602
+ // this.createNewTemplateDialog();
1603
+ // }, 2000);
1604
+ }
1605
+ createNewTemplateDialog(stData = null) {
1606
+ if (!this.componentName)
1607
+ return;
1608
+ let data = {
1609
+ name: stData ? stData.name : null,
1610
+ enableStickiness: stData ? stData.enableStickiness : false,
1611
+ fromStartColumnNumber: stData ? stData.fromStartColumnNumber : 0,
1612
+ fromEndColumnNumber: stData ? stData.fromEndColumnNumber : 0,
1613
+ listComponentName: this.componentName,
1614
+ selectedTemplateId: stData ? stData?.id : null,
1615
+ defaultSelectedState: stData && stData?.id ? false : true,
1616
+ defaultColumns: this.defaultColumns,
1617
+ columns: this.columns,
1618
+ displayColumns: stData ? stData?.displayColumns?.split(',') : this.displayedColumns,
1619
+ t: this.t,
1620
+ skipTranslation: this.skipTranslation,
1621
+ customColumns: this.customColumns,
1622
+ columnCustomizationUrlConfig: this.columnCustomizationUrlConfig
1623
+ };
1624
+ const dialogRef = this.dialog.open(CreateColumnsTemplateComponent, {
1625
+ width: "35%",
1626
+ minWidth: '370px',
1627
+ data: data,
1628
+ panelClass: ['angular-create-new-columns-template'],
1629
+ disableClose: true,
1630
+ });
1631
+ dialogRef.afterClosed().subscribe((res) => {
1632
+ if (res) {
1633
+ console.log("=== createNewTemplateDialog ===", res);
1634
+ if (res?.isUpdated) {
1635
+ this.templates = this.templates?.map(t => {
1636
+ if (t.id == res?.id) {
1637
+ t = res;
1638
+ }
1639
+ return t;
1640
+ });
1641
+ }
1642
+ else {
1643
+ this.templates = [res, ...this.templates];
1644
+ }
1645
+ this.selectedTemplate = res;
1646
+ this.selectedTemplateChange.emit(this.selectedTemplate);
1647
+ this.changeDisplayColumns();
1648
+ }
1649
+ });
1650
+ }
1651
+ getColumnsTemplates() {
1652
+ this.userCustomizationService.getColumnsTemplates(this.columnCustomizationUrlConfig.list, this.componentName).subscribe(r => {
1653
+ console.log("getColumnsTemplates:", r.data);
1654
+ this.templates = r?.data ?? [];
1655
+ setTimeout(() => {
1656
+ this.getSelectedColumnsTemplate();
1657
+ }, 100);
1658
+ });
1659
+ }
1660
+ getSelectedColumnsTemplate() {
1661
+ this.userCustomizationService.getSelectedColumnsTemplate(this.columnCustomizationUrlConfig.getSelectedTemplate, this.componentName).subscribe((r) => {
1662
+ console.log("getSelectedColumnsTemplate:", r.data);
1663
+ if (r?.data && Object.keys(r?.data).length != 0) {
1664
+ if (r.data?.listComponentColumnsTemplateId > 0) {
1665
+ this.selectedTemplate = this.templates?.find((t) => t.id == r.data?.listComponentColumnsTemplateId);
1666
+ this.selectedTemplateChange.emit(this.selectedTemplate);
1667
+ }
1668
+ console.log("getSelectedColumnsTemplate:", this.templates, this.selectedTemplate);
1669
+ this.changeDisplayColumns();
1670
+ }
1671
+ });
1672
+ }
1673
+ onSelectedTemplate(templateId) {
1674
+ setTimeout(() => {
1675
+ if (this.isDeleteTemplate) {
1676
+ console.log("onSelectedTemplate:", this.isDeleteTemplate);
1677
+ let confirmBoxData = {
1678
+ title: this.t?.deleteColumnsTemplate?.title,
1679
+ message: this.t?.deleteColumnsTemplate?.message,
1680
+ iconClass: "angular-text-danger",
1681
+ icon: "delete",
1682
+ approveButtonText: this.t?.deleteColumnsTemplate?.yes,
1683
+ approveButtonClass: "angular-btn-danger",
1684
+ cancelButtonText: this.t?.deleteColumnsTemplate?.no,
1685
+ cancelButtonClass: "angular-btn-primary"
1686
+ };
1687
+ const dialogRef = this.dialog.open(AngularSmartDataTableConfirmationDialogComponent, {
1688
+ width: "30%",
1689
+ minWidth: '370px',
1690
+ // panelClass: ['angular-simple-confirmation'],
1691
+ data: confirmBoxData,
1692
+ disableClose: true,
1693
+ });
1694
+ dialogRef.afterClosed().subscribe((result) => {
1695
+ console.log("The dialog was closed with result:", result);
1696
+ if (result) {
1697
+ this.userCustomizationService.deleteColumnsTemplate(this.columnCustomizationUrlConfig.delete, { id: templateId, isSelectedTemplate: this.selectedTemplate?.id == templateId }).subscribe((r) => {
1698
+ this.helper.showSuccessMsg('Columns template has been deleted successfully', 'Done');
1699
+ this.templates.splice(this.templates.findIndex(ee => ee.id == templateId), 1);
1700
+ if (this.selectedTemplate?.id == templateId) {
1701
+ this.selectedTemplate = {
1702
+ id: -1,
1703
+ name: 'Default',
1704
+ fromStartColumnNumber: 0,
1705
+ fromEndColumnNumber: 0,
1706
+ };
1707
+ this.selectedTemplateChange.emit(this.selectedTemplate);
1708
+ this.changeDisplayColumns();
1709
+ }
1710
+ }, err => this.helper.showHttpErrorMsg(err));
1711
+ }
1712
+ });
1713
+ }
1714
+ else if (this.isEditTemplate) {
1715
+ console.log("onSelectedTemplate:", this.isEditTemplate);
1716
+ let st = this.templates?.find((t) => t.id == templateId);
1717
+ this.createNewTemplateDialog(st);
1718
+ }
1719
+ else {
1720
+ if (this.selectedTemplate?.id != templateId) {
1721
+ if (templateId > 0) {
1722
+ this.selectedTemplate = this.templates?.find((t) => t.id == templateId);
1723
+ }
1724
+ else {
1725
+ this.selectedTemplate = {
1726
+ id: -1,
1727
+ name: 'Default'
1728
+ };
1729
+ }
1730
+ this.selectedTemplateChange.emit(this.selectedTemplate);
1731
+ this.userCustomizationService.updateSelectedColumnsTemplate(this.columnCustomizationUrlConfig.updateSelectedTemplate, { id: this.selectedTemplate?.id, listComponentName: this.componentName }).subscribe((r) => {
1732
+ this.changeDisplayColumns();
1733
+ });
1734
+ }
1735
+ }
1736
+ this.isDeleteTemplate = false;
1737
+ this.isEditTemplate = false;
1738
+ }, 200);
1739
+ }
1740
+ changeDisplayColumns() {
1741
+ if (this.selectedTemplate?.id > 0) {
1742
+ this.displayedColumns = this.selectedTemplate.displayColumns?.split(',');
1743
+ }
1744
+ else {
1745
+ this.displayedColumns = this.defaultColumns;
1746
+ }
1747
+ this.displayedColumnsChange.emit(this.displayedColumns);
1748
+ this.fromStartColumnNumberChange.emit(this.selectedTemplate?.fromStartColumnNumber ?? 0);
1749
+ this.fromEndColumnNumberChange.emit(this.selectedTemplate?.fromEndColumnNumber ?? 0);
1750
+ }
1751
+ onMouseOverOut(event, color) {
1752
+ const target = event.target;
1753
+ target.style.color = color;
1754
+ }
1755
+ onMouseOut(event) {
1756
+ const target = event.target;
1757
+ target.style.color = `color: var(--angular-primary, var(--mat-sys-primary, #3838a2)) !important;`;
1758
+ }
1759
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularColumnsBtnComponent, deps: [{ token: AngularHelperService }, { token: UserCustomizationService }, { token: i1$1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
1760
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.7", type: AngularColumnsBtnComponent, isStandalone: false, selector: "angular-columns-btn", inputs: { columnCustomizationUrlConfig: "columnCustomizationUrlConfig", t: "t", componentName: "componentName", defaultColumns: "defaultColumns", columns: "columns", skipTranslation: "skipTranslation", customColumns: "customColumns", selectedTemplate: "selectedTemplate" }, outputs: { selectedTemplateChange: "selectedTemplateChange", displayedColumnsChange: "displayedColumnsChange", fromStartColumnNumberChange: "fromStartColumnNumberChange", fromEndColumnNumberChange: "fromEndColumnNumberChange" }, ngImport: i0, template: "<!-- shared.angularColumnsBtnComponent -->\n<button mat-flat-button class=\"angular-columns-btn\" style=\"background-color: var(--angular-light, #f5f5f5); color: black;\" [matMenuTriggerFor]=\"menu\">\n <mat-icon>view_week</mat-icon>\n <span style=\"display: flex; flex-direction: row;\">\n {{selectedTemplate?.name}}\n <mat-icon style=\"width: 15px; height: 15px; font-size: 20px; line-height: 16px;\">arrow_drop_down</mat-icon>\n </span>\n</button>\n<mat-menu #menu=\"matMenu\" class=\"angular-columns-btn-mat-menu\">\n <button mat-menu-item (click)=\"selectedTemplate?.id != -1 ? onSelectedTemplate(-1) : null\">\n <mat-icon>{{selectedTemplate?.id == -1 ? 'done': ''}}</mat-icon>\n Default\n </button>\n <button mat-menu-item *ngFor=\"let template of templates\" (click)=\"onSelectedTemplate(template?.id)\">\n <mat-icon>{{template?.id == selectedTemplate?.id ? 'done': ''}}</mat-icon>\n <span style=\"padding-right: 4rem;\">{{template.name}}</span>\n <mat-icon style=\"position: absolute; right: 0;\" class=\"delete-button\" (mouseover)=\"onMouseOverOut($event, `var(--angular-delete-icon, #bb333b)`)\" (mouseout)=\"onMouseOverOut($event, '')\" (click)=\"isDeleteTemplate = true\">delete</mat-icon>\n <mat-icon style=\"position: absolute; right: 2rem;\" class=\"edit-button\" (mouseover)=\"onMouseOverOut($event, `var(--angular-edit-icon, var(--mat-sys-primary, #3838a2))`)\" (mouseout)=\"onMouseOverOut($event, '')\" (click)=\"isEditTemplate = true\">edit</mat-icon>\n </button>\n <mat-divider class=\"angular-mat-divider\" style=\"margin: 0px;\"></mat-divider>\n <button mat-menu-item class=\"angular-create-columns-template-button\" style=\"color: var(--angular-primary, var(--mat-sys-primary, #3838a2));\" (click)=\"createNewTemplateDialog()\"><mat-icon style=\"color: var(--angular-primary, var(--mat-sys-primary, #3838a2));\">add</mat-icon> {{t?.angularColumnsBtnComponent?.createNewView}}</button>\n</mat-menu>", styles: [""], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i7.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: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.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: i8$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }] });
1761
+ }
1762
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularColumnsBtnComponent, decorators: [{
1763
+ type: Component,
1764
+ args: [{ selector: 'angular-columns-btn', standalone: false, template: "<!-- shared.angularColumnsBtnComponent -->\n<button mat-flat-button class=\"angular-columns-btn\" style=\"background-color: var(--angular-light, #f5f5f5); color: black;\" [matMenuTriggerFor]=\"menu\">\n <mat-icon>view_week</mat-icon>\n <span style=\"display: flex; flex-direction: row;\">\n {{selectedTemplate?.name}}\n <mat-icon style=\"width: 15px; height: 15px; font-size: 20px; line-height: 16px;\">arrow_drop_down</mat-icon>\n </span>\n</button>\n<mat-menu #menu=\"matMenu\" class=\"angular-columns-btn-mat-menu\">\n <button mat-menu-item (click)=\"selectedTemplate?.id != -1 ? onSelectedTemplate(-1) : null\">\n <mat-icon>{{selectedTemplate?.id == -1 ? 'done': ''}}</mat-icon>\n Default\n </button>\n <button mat-menu-item *ngFor=\"let template of templates\" (click)=\"onSelectedTemplate(template?.id)\">\n <mat-icon>{{template?.id == selectedTemplate?.id ? 'done': ''}}</mat-icon>\n <span style=\"padding-right: 4rem;\">{{template.name}}</span>\n <mat-icon style=\"position: absolute; right: 0;\" class=\"delete-button\" (mouseover)=\"onMouseOverOut($event, `var(--angular-delete-icon, #bb333b)`)\" (mouseout)=\"onMouseOverOut($event, '')\" (click)=\"isDeleteTemplate = true\">delete</mat-icon>\n <mat-icon style=\"position: absolute; right: 2rem;\" class=\"edit-button\" (mouseover)=\"onMouseOverOut($event, `var(--angular-edit-icon, var(--mat-sys-primary, #3838a2))`)\" (mouseout)=\"onMouseOverOut($event, '')\" (click)=\"isEditTemplate = true\">edit</mat-icon>\n </button>\n <mat-divider class=\"angular-mat-divider\" style=\"margin: 0px;\"></mat-divider>\n <button mat-menu-item class=\"angular-create-columns-template-button\" style=\"color: var(--angular-primary, var(--mat-sys-primary, #3838a2));\" (click)=\"createNewTemplateDialog()\"><mat-icon style=\"color: var(--angular-primary, var(--mat-sys-primary, #3838a2));\">add</mat-icon> {{t?.angularColumnsBtnComponent?.createNewView}}</button>\n</mat-menu>" }]
1765
+ }], ctorParameters: () => [{ type: AngularHelperService }, { type: UserCustomizationService }, { type: i1$1.MatDialog }], propDecorators: { columnCustomizationUrlConfig: [{
1766
+ type: Input,
1767
+ args: [{ required: true }]
1768
+ }], t: [{
1769
+ type: Input
1770
+ }], componentName: [{
1771
+ type: Input,
1772
+ args: [{ required: true }]
1773
+ }], defaultColumns: [{
1774
+ type: Input,
1775
+ args: [{ required: true }]
1776
+ }], columns: [{
1777
+ type: Input,
1778
+ args: [{ required: true }]
1779
+ }], skipTranslation: [{
1780
+ type: Input
1781
+ }], customColumns: [{
1782
+ type: Input
1783
+ }], selectedTemplate: [{
1784
+ type: Input
1785
+ }], selectedTemplateChange: [{
1786
+ type: Output
1787
+ }], displayedColumnsChange: [{
1788
+ type: Output
1789
+ }], fromStartColumnNumberChange: [{
1790
+ type: Output
1791
+ }], fromEndColumnNumberChange: [{
1792
+ type: Output
1793
+ }] } });
1794
+
1795
+ class AngularDatePipe {
1796
+ transform(value, format) {
1797
+ const fmt = format || 'dd MMM yyyy';
1798
+ // Empty / "no date" inputs render blank (0 and "0" are treated as no-date).
1799
+ if (value === null || value === undefined || value === '' || value === 0 || value === '0') {
1800
+ return '';
1801
+ }
1802
+ let dt;
1803
+ if (value instanceof Date) {
1804
+ dt = DateTime.fromJSDate(value);
1805
+ }
1806
+ else if (typeof value === 'number') {
1807
+ dt = DateTime.fromMillis(value);
1808
+ }
1809
+ else if (typeof value === 'string') {
1810
+ const num = Number(value);
1811
+ // Numeric string => epoch millis (unchanged); non-numeric => ISO date.
1812
+ dt = !isNaN(num) ? DateTime.fromMillis(num) : DateTime.fromISO(value);
1813
+ }
1814
+ else {
1815
+ return '';
1816
+ }
1817
+ // Invalid inputs render blank instead of the literal "Invalid Date".
1818
+ return dt.isValid ? dt.toFormat(fmt) : '';
1819
+ }
1820
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularDatePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1821
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.7", ngImport: i0, type: AngularDatePipe, isStandalone: false, name: "angularDate" });
1822
+ }
1823
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularDatePipe, decorators: [{
1824
+ type: Pipe,
1825
+ args: [{
1826
+ name: 'angularDate',
1827
+ standalone: false
1828
+ }]
1829
+ }] });
1830
+
1831
+ class AngularDateTimePipe {
1832
+ transform(value, format) {
1833
+ const fmt = format || 'dd MMM yyyy hh:mm a';
1834
+ // Empty / "no date" inputs render blank (0 and "0" are treated as no-date).
1835
+ if (value === null || value === undefined || value === '' || value === 0 || value === '0') {
1836
+ return '';
1837
+ }
1838
+ let dt;
1839
+ if (value instanceof Date) {
1840
+ dt = DateTime.fromJSDate(value);
1841
+ }
1842
+ else if (typeof value === 'number') {
1843
+ dt = DateTime.fromMillis(value);
1844
+ }
1845
+ else if (typeof value === 'string') {
1846
+ const num = Number(value);
1847
+ // Numeric string => epoch millis (unchanged); non-numeric => ISO date.
1848
+ dt = !isNaN(num) ? DateTime.fromMillis(num) : DateTime.fromISO(value);
1849
+ }
1850
+ else {
1851
+ return '';
1852
+ }
1853
+ // Invalid inputs render blank instead of the literal "Invalid Date".
1854
+ return dt.isValid ? dt.toFormat(fmt) : '';
1855
+ }
1856
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularDateTimePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1857
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.7", ngImport: i0, type: AngularDateTimePipe, isStandalone: false, name: "angularDateTime" });
1858
+ }
1859
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularDateTimePipe, decorators: [{
1860
+ type: Pipe,
1861
+ args: [{
1862
+ name: 'angularDateTime',
1863
+ standalone: false
1864
+ }]
1865
+ }] });
1866
+
1867
+ class AngularDateTimeWithSecondsPipe {
1868
+ transform(value, format) {
1869
+ const fmt = format || 'dd MMM yyyy hh:mm:ss a';
1870
+ // Empty / "no date" inputs render blank (0 and "0" are treated as no-date).
1871
+ if (value === null || value === undefined || value === '' || value === 0 || value === '0') {
1872
+ return '';
1873
+ }
1874
+ let dt;
1875
+ if (value instanceof Date) {
1876
+ dt = DateTime.fromJSDate(value);
1877
+ }
1878
+ else if (typeof value === 'number') {
1879
+ dt = DateTime.fromMillis(value);
1880
+ }
1881
+ else if (typeof value === 'string') {
1882
+ const num = Number(value);
1883
+ // Numeric string => epoch millis (unchanged); non-numeric => ISO date.
1884
+ dt = !isNaN(num) ? DateTime.fromMillis(num) : DateTime.fromISO(value);
1885
+ }
1886
+ else {
1887
+ return '';
1888
+ }
1889
+ // Invalid inputs render blank instead of the literal "Invalid Date".
1890
+ return dt.isValid ? dt.toFormat(fmt) : '';
1891
+ }
1892
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularDateTimeWithSecondsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1893
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.7", ngImport: i0, type: AngularDateTimeWithSecondsPipe, isStandalone: false, name: "angularDateTimeWithSeconds" });
1894
+ }
1895
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularDateTimeWithSecondsPipe, decorators: [{
1896
+ type: Pipe,
1897
+ args: [{
1898
+ name: 'angularDateTimeWithSeconds',
1899
+ standalone: false
1900
+ }]
1901
+ }] });
1902
+
1903
+ class AngularCurrencyPipe {
1904
+ transform(value, decimals = 2) {
1905
+ // Support string decimals passed from template format config
1906
+ if (typeof decimals === 'string') {
1907
+ decimals = parseInt(decimals, 10);
1908
+ if (isNaN(decimals))
1909
+ decimals = 2;
1910
+ }
1911
+ // Handle null, undefined, or empty values
1912
+ if (value === null || value === undefined || value === '') {
1913
+ return '';
1914
+ }
1915
+ // Convert to number
1916
+ const numValue = typeof value === 'string' ? parseFloat(value) : value;
1917
+ // Handle invalid numbers
1918
+ if (isNaN(numValue)) {
1919
+ return '';
1920
+ }
1921
+ // Round to specified decimal places
1922
+ const fixedValue = numValue.toFixed(decimals);
1923
+ // Split into integer and decimal parts
1924
+ const [integerPart, decimalPart] = fixedValue.split('.');
1925
+ // Add commas every 3 digits
1926
+ const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
1927
+ // Return formatted value with decimal part
1928
+ return decimalPart ? `${formattedInteger}.${decimalPart}` : formattedInteger;
1929
+ }
1930
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularCurrencyPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1931
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.7", ngImport: i0, type: AngularCurrencyPipe, isStandalone: false, name: "angularCurrency" });
1932
+ }
1933
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularCurrencyPipe, decorators: [{
1934
+ type: Pipe,
1935
+ args: [{
1936
+ name: 'angularCurrency',
1937
+ standalone: false
1938
+ }]
1939
+ }] });
1940
+
1941
+ class AngularSmartDataTableComponent {
1942
+ dialog;
1943
+ apiService;
1944
+ route;
1945
+ router;
1946
+ location;
1947
+ breakpointObserver;
1948
+ cdr;
1949
+ homeUrl = '';
1950
+ columnCustomizationUrlConfig;
1951
+ t = {};
1952
+ componentName = '';
1953
+ mainTitle;
1954
+ searchPlaceholder;
1955
+ breadcrumbs = [];
1956
+ hideHeader = false;
1957
+ hideTableHeader = false;
1958
+ hidePaginator = false;
1959
+ keepFilterInUrl = true;
1960
+ disableBorderedView = false;
1961
+ displayColumnsSelectionButton = true;
1962
+ loadDataApiBaseUrl;
1963
+ startStickyColumnCount;
1964
+ endStickyColumnCount;
1965
+ isSearchFieldMobileResponsive = true;
1966
+ isMobileResponsiveTable = false;
1967
+ loaderPosition = 'top';
1968
+ dataNotFoundConfig = {
1969
+ title: 'No Data Found',
1970
+ desc: 'There is no data. Please click on button to add',
1971
+ btnText: 'Add New',
1972
+ btnUrl: '',
1973
+ btnClick: null,
1974
+ secondBtnText: '',
1975
+ secondBtnUrl: '',
1976
+ secondBtnClick: null
1977
+ };
1978
+ showFilterButtonSection;
1979
+ /** Optional per-column format config. Key = column name, Value = format string. Defaults to empty (uses built-in formats). */
1980
+ columnValueTypeFormats = {};
1981
+ columnsCodeMapping;
1982
+ autoRenderColumns;
1983
+ templateRenderColumns;
1984
+ defaultDisplayedColumns;
1985
+ displayedColumns;
1986
+ defaultColumns;
1987
+ columns;
1988
+ displayedColumnsChange = new EventEmitter();
1989
+ usersColumnSelectionDetail;
1990
+ defaultSortObj = {};
1991
+ sortObj = {};
1992
+ sortObjChange = new EventEmitter();
1993
+ loadingSpinnerDiameter = 30;
1994
+ pageSizeOptions = [5, 10, 25, 100];
1995
+ pageSize = 10;
1996
+ pageSizeChange = new EventEmitter();
1997
+ useGlobalPageSize = true;
1998
+ pageIndex = 0;
1999
+ pageIndexChange = new EventEmitter();
2000
+ filterFormGroup = new FormGroup({});
2001
+ rowsConfig = {
2002
+ backgroundApplyFunction: () => null // Default blank function
2003
+ };
2004
+ onDataLoaded = new EventEmitter();
2005
+ onSetExtraData = new EventEmitter();
2006
+ onSetTotal = new EventEmitter();
2007
+ hasSelectedAllRows = false;
2008
+ selectedTemplate = {
2009
+ id: -1,
2010
+ name: 'Default',
2011
+ fromStartColumnNumber: 0,
2012
+ fromEndColumnNumber: 0,
2013
+ };
2014
+ selectedFilterValues = [];
2015
+ finalSelectedFilterValuesToDisplay = [];
2016
+ selectedFilterGroupedValues = [];
2017
+ isShowFilter = false;
2018
+ filterFormGroupSubscription;
2019
+ filterHasNonEmptyValue = false;
2020
+ filterApplied = false;
2021
+ resetFlag = false;
2022
+ initialLoading = true;
2023
+ displayAfterFilterRemoved = false;
2024
+ filterFromQueryParams = {};
2025
+ sortFromQueryParams = {};
2026
+ search = '';
2027
+ searchCtrl = new FormControl();
2028
+ _onDestroy = new Subject();
2029
+ // Additional subscriptions that need cleanup
2030
+ _selectionSubscription;
2031
+ _handsetSubscription;
2032
+ _queryParamsSubscription;
2033
+ // Memory-efficient caching
2034
+ _columnMappingCache = new Map();
2035
+ _displayedColumnsCache = [];
2036
+ _lastColumnsCodeMappingHash = '';
2037
+ // Race condition prevention
2038
+ _currentRequestSubject = new Subject();
2039
+ // Timeout management for proper cleanup - prevent memory leaks
2040
+ timeoutManager = new TimeoutManager();
2041
+ // Computed row backgrounds for optimal performance
2042
+ computedRowBackgrounds = new Map();
2043
+ dataSource;
2044
+ _table;
2045
+ set table(value) {
2046
+ this._table = value;
2047
+ // ✅ FIX: When table becomes available, connect it to datasource if it exists
2048
+ if (this._table && this.dataSource) {
2049
+ // Force the table to connect to our datasource
2050
+ this._table.dataSource = this.dataSource;
2051
+ }
2052
+ }
2053
+ _sort;
2054
+ _sortSubscription;
2055
+ set sort(value) {
2056
+ this._sort = value;
2057
+ if (this._sort) {
2058
+ if (this._sortSubscription) {
2059
+ this._sortSubscription.unsubscribe();
2060
+ }
2061
+ this._sortSubscription = this._sort.sortChange.pipe(takeUntil(this._onDestroy)).subscribe((ch) => {
2062
+ this.handleSortingChanges(ch);
2063
+ });
2064
+ }
2065
+ }
2066
+ _paginator;
2067
+ _paginatorSubscription;
2068
+ set paginator(value) {
2069
+ this._paginator = value;
2070
+ if (this._paginator) {
2071
+ if (this._paginatorSubscription) {
2072
+ this._paginatorSubscription.unsubscribe();
2073
+ }
2074
+ this._paginatorSubscription = this._paginator.page.pipe(takeUntil(this._onDestroy), tap(() => {
2075
+ this.onPaginationChanges();
2076
+ })).subscribe();
2077
+ }
2078
+ }
2079
+ loadingSubscription;
2080
+ dataLengthSubscription;
2081
+ enableRowsSelection = false;
2082
+ enableAllRowsSelection = false;
2083
+ onlySingleSelection = false;
2084
+ selectedRowIds;
2085
+ selectedRowKey = 'id';
2086
+ selectedRows;
2087
+ selectedRowsChange = new EventEmitter();
2088
+ selection = new SelectionModel(true, []);
2089
+ selectedIds = new Set();
2090
+ isAllRowsSelected = false;
2091
+ allRowsSelectedChange = new EventEmitter(false);
2092
+ enableDragNDrop = false;
2093
+ listDataSequenceChange = new EventEmitter();
2094
+ isExpansion = false;
2095
+ isExpandedRow = false;
2096
+ expandedTemplate;
2097
+ isExpansionForMobileResponsive = false;
2098
+ isExpandedRowForMobileResponsive = false;
2099
+ expandedTemplateForMobileResponsive;
2100
+ headerTemplateForEachRowForMobileResponsive;
2101
+ isAllExpanded = false;
2102
+ isAllExpandedForMobileResponsive = false;
2103
+ // Expansion state management - avoid direct mutation
2104
+ expandedRowIds = new Set();
2105
+ expandedRowIdsForMobileResponsive = new Set();
2106
+ isHandset$;
2107
+ isMobile = false;
2108
+ constructor(
2109
+ // private userCustomizationService: UserCustomizationService,
2110
+ dialog, apiService, route, router, location, breakpointObserver, cdr) {
2111
+ this.dialog = dialog;
2112
+ this.apiService = apiService;
2113
+ this.route = route;
2114
+ this.router = router;
2115
+ this.location = location;
2116
+ this.breakpointObserver = breakpointObserver;
2117
+ this.cdr = cdr;
2118
+ // Store subscription reference for proper cleanup
2119
+ this._selectionSubscription = this.selection.changed.subscribe(change => {
2120
+ change.added.forEach(item => {
2121
+ if (item && item[this.selectedRowKey] !== undefined) {
2122
+ this.selectedIds.add(item[this.selectedRowKey]);
2123
+ }
2124
+ });
2125
+ change.removed.forEach(item => {
2126
+ if (item && item[this.selectedRowKey] !== undefined) {
2127
+ this.selectedIds.delete(item[this.selectedRowKey]);
2128
+ }
2129
+ });
2130
+ });
2131
+ }
2132
+ ngOnInit() {
2133
+ this.isHandset$ = this.breakpointObserver.observe([Breakpoints.Handset])
2134
+ .pipe(map(result => result.matches), shareReplay());
2135
+ this._handsetSubscription = this.isHandset$.subscribe(r => {
2136
+ this.isMobile = r;
2137
+ });
2138
+ this.setDefaultColumns();
2139
+ this.getHomeUrl();
2140
+ this._queryParamsSubscription = this.route.queryParams.subscribe(qp => {
2141
+ // Initialize objects
2142
+ this.filterFromQueryParams = {};
2143
+ this.sortFromQueryParams = {};
2144
+ if (this.keepFilterInUrl) {
2145
+ const { filterParams, sortParams, pageIndex, pageSize, search } = QueryParamsHelper.processForFilters(qp, this.columnsCodeMapping);
2146
+ this.filterFromQueryParams = filterParams;
2147
+ this.sortFromQueryParams = sortParams;
2148
+ this.pageIndex = pageIndex;
2149
+ this.pageSize = pageSize;
2150
+ this.search = search;
2151
+ this.searchCtrl.patchValue(this.search);
2152
+ this.filterFormGroup.patchValue(this.filterFromQueryParams);
2153
+ if (ValidationHelper.hasProperty(this.sortFromQueryParams, 'sortBy') &&
2154
+ ValidationHelper.hasProperty(this.sortFromQueryParams, 'sortOrder')) {
2155
+ this.sortObj = this.sortFromQueryParams;
2156
+ this.sortObjChange.emit(this.sortObj);
2157
+ }
2158
+ }
2159
+ this.filterApplied = ValidationHelper.hasNonEmptyValue(this.filterFromQueryParams);
2160
+ this.getList();
2161
+ });
2162
+ this.searchCtrl.valueChanges
2163
+ .pipe(takeUntil(this._onDestroy), debounceTime(400), distinctUntilChanged())
2164
+ .subscribe((search) => {
2165
+ this.search = search;
2166
+ this.resetFlag = true; // B/c every time search is made, make sure we go to first page...
2167
+ this.getList(false);
2168
+ });
2169
+ }
2170
+ ngOnChanges(changes) {
2171
+ // console.log(`[table-list-view-wrapper]: ngOnChanges:`, changes);
2172
+ if (changes['defaultDisplayedColumns']) {
2173
+ this.handleDisplayedColumns('defaultDisplayedColumns');
2174
+ }
2175
+ if (changes['columnsCodeMapping']) {
2176
+ this.columnsCodeMapping = changes['columnsCodeMapping'].currentValue;
2177
+ this.handleDisplayedColumns('columnsCodeMapping');
2178
+ this.columns = this.columnsCodeMapping.map(c => c.name);
2179
+ this.autoRenderColumns = this.columnsCodeMapping.filter(c => c.hasOwnProperty('valueKey'));
2180
+ this.templateRenderColumns = this.columnsCodeMapping.filter(c => c.hasOwnProperty('template'));
2181
+ }
2182
+ if (changes['pageIndex']) {
2183
+ this.pageIndex = changes['pageIndex'].currentValue;
2184
+ }
2185
+ if (changes['pageSize']) {
2186
+ if (!changes['pageSize'].isFirstChange) {
2187
+ this.pageSize = changes['pageSize'].currentValue;
2188
+ }
2189
+ else {
2190
+ if (this.useGlobalPageSize) {
2191
+ let userDefaultPageSize = getFromLocalStorageWithExpiry('user_pagination_page_size');
2192
+ this.pageSize = userDefaultPageSize ? userDefaultPageSize : changes['pageSize'].currentValue;
2193
+ }
2194
+ }
2195
+ }
2196
+ if (changes['loadDataApiBaseUrl']) {
2197
+ if (changes['loadDataApiBaseUrl'].currentValue) {
2198
+ // Clean up existing subscriptions
2199
+ if (this.loadingSubscription) {
2200
+ this.loadingSubscription.unsubscribe();
2201
+ }
2202
+ if (this.dataLengthSubscription) {
2203
+ this.dataLengthSubscription.unsubscribe();
2204
+ }
2205
+ // ✅ FIX: Only create datasource once on initialization
2206
+ // Reusing the same datasource prevents subscription issues
2207
+ if (!this.dataSource) {
2208
+ this.dataSource = new ApiDataSource(this.apiService);
2209
+ // Template binding [dataSource]="dataSource" will handle the connection
2210
+ }
2211
+ this.loadingSubscription = this.dataSource.loading$.subscribe(loading => {
2212
+ if (!loading) {
2213
+ if (this._paginator) {
2214
+ this._paginator.pageIndex = this.pageIndex;
2215
+ this._paginator.pageSize = this.pageSize;
2216
+ }
2217
+ // ✅ FIX: Always clear caches when new data arrives (even if empty)
2218
+ // Clear background cache when new data arrives
2219
+ this.clearRowBackgroundCache();
2220
+ // Pre-compute all row backgrounds for optimal performance
2221
+ this.computeAllRowBackgrounds();
2222
+ // ✅ FIX: Ensure selection state is updated even when data changes from empty to populated
2223
+ this.checkAllRowsSelected();
2224
+ // ✅ FIX: Force Angular change detection to ensure table re-renders
2225
+ // This is critical for data → empty → data transitions
2226
+ this.cdr.detectChanges();
2227
+ // ✅ FIX: Force MatTable to re-render rows after data transitions
2228
+ // This ensures rows are properly rendered when going from empty → data
2229
+ if (this._table) {
2230
+ this._table.renderRows();
2231
+ }
2232
+ // ✅ FIX: Force change detection by emitting events
2233
+ this.onDataLoaded.emit(true);
2234
+ this.onSetExtraData.emit(this.dataSource.extraDataSubject.value);
2235
+ // if (this.selectedRowIds && this.selectedRowIds.length) {
2236
+ // setTimeout(() => {
2237
+ // this.setSelectedRows();
2238
+ // }, 200);
2239
+ // }
2240
+ }
2241
+ });
2242
+ this.dataLengthSubscription = this.dataSource.totalDataLength$.subscribe((total) => {
2243
+ if (total !== null) {
2244
+ this.initialLoading = false;
2245
+ this.onSetTotal.emit(total);
2246
+ // console.log('[table-list-view-wrapper]: dataSource total total:', total);
2247
+ }
2248
+ });
2249
+ }
2250
+ }
2251
+ if (changes['filterFormGroup']) {
2252
+ if (this.filterFormGroupSubscription) {
2253
+ this.filterFormGroupSubscription.unsubscribe();
2254
+ }
2255
+ // ✅ FIX: Use custom comparator for distinctUntilChanged to properly detect form value changes
2256
+ this.filterFormGroupSubscription = this.filterFormGroup.valueChanges
2257
+ .pipe(takeUntil(this._onDestroy), distinctUntilChanged((prev, curr) => {
2258
+ // Custom comparator: deep compare form values
2259
+ return JSON.stringify(prev) === JSON.stringify(curr);
2260
+ })).subscribe(val => {
2261
+ this.filterHasNonEmptyValue = ValidationHelper.hasNonEmptyValue(val);
2262
+ });
2263
+ }
2264
+ if (changes['selectedRows']) {
2265
+ this.selectedRows = changes['selectedRows'].currentValue;
2266
+ if (this.selectedRows && this.selectedRows.length) {
2267
+ // TODO:: Leave for now..... (Not able to decide whether in future we need to pass whole row or ids only)
2268
+ }
2269
+ }
2270
+ if (changes['selectedRowIds']) {
2271
+ this.selectedRowIds = changes['selectedRowIds'].currentValue;
2272
+ if (this.selectedRowIds && this.selectedRowIds.length) {
2273
+ this.setSelectedRows();
2274
+ }
2275
+ }
2276
+ if (changes['defaultSortObj']?.currentValue) {
2277
+ this.defaultSortObj = changes['defaultSortObj'].currentValue;
2278
+ this.handleSortingChanges({
2279
+ direction: this.defaultSortObj.sortOrder,
2280
+ active: this.defaultSortObj.sortBy
2281
+ });
2282
+ }
2283
+ }
2284
+ ngOnDestroy() {
2285
+ // Complete the destroy subject first to trigger takeUntil operators
2286
+ this._onDestroy.next();
2287
+ this._onDestroy.complete();
2288
+ // Clean up all subscriptions
2289
+ this._sortSubscription?.unsubscribe();
2290
+ this._paginatorSubscription?.unsubscribe();
2291
+ this.loadingSubscription?.unsubscribe();
2292
+ this.dataLengthSubscription?.unsubscribe();
2293
+ this.filterFormGroupSubscription?.unsubscribe();
2294
+ // Clean up additional subscriptions
2295
+ this._selectionSubscription?.unsubscribe();
2296
+ this._handsetSubscription?.unsubscribe();
2297
+ this._queryParamsSubscription?.unsubscribe();
2298
+ // Clean up selection model and data structures using CollectionHelper
2299
+ this.selection.clear();
2300
+ CollectionHelper.clearSet(this.selectedIds);
2301
+ CollectionHelper.clearSet(this.expandedRowIds);
2302
+ CollectionHelper.clearSet(this.expandedRowIdsForMobileResponsive);
2303
+ // Clear arrays to free memory using CollectionHelper
2304
+ CollectionHelper.clearArray(this.selectedFilterValues);
2305
+ CollectionHelper.clearArray(this.finalSelectedFilterValuesToDisplay);
2306
+ CollectionHelper.clearArray(this.selectedFilterGroupedValues);
2307
+ CollectionHelper.clearArray(this.displayedColumns);
2308
+ // Clear caches to free memory
2309
+ CollectionHelper.clearMap(this._columnMappingCache);
2310
+ CollectionHelper.clearArray(this._displayedColumnsCache);
2311
+ this._lastColumnsCodeMappingHash = '';
2312
+ CollectionHelper.clearMap(this.computedRowBackgrounds);
2313
+ // Complete race condition prevention subject
2314
+ this._currentRequestSubject.next();
2315
+ this._currentRequestSubject.complete();
2316
+ // Clear all pending timeouts to prevent memory leaks
2317
+ this.timeoutManager.clearAll();
2318
+ // Disconnect data source to stop API calls and complete observables
2319
+ if (this.dataSource) {
2320
+ this.dataSource.disconnect({});
2321
+ }
2322
+ }
2323
+ setDefaultColumns() {
2324
+ if (this.defaultDisplayedColumns && this.defaultDisplayedColumns.length) {
2325
+ this.defaultColumns = this.defaultDisplayedColumns;
2326
+ }
2327
+ else {
2328
+ this.defaultColumns = this.columnsCodeMapping.map(c => c.name);
2329
+ }
2330
+ }
2331
+ handleDisplayedColumns(msg = '') {
2332
+ if (this.selectedTemplate?.id > 0 && this.defaultDisplayedColumns && this.defaultDisplayedColumns.length) {
2333
+ this.displayedColumns = this.defaultDisplayedColumns.filter(c => this._columnMappingCache.has(c));
2334
+ }
2335
+ else {
2336
+ // Create a hash of current columns to check if cache is valid
2337
+ const columnsHash = JSON.stringify(this.columnsCodeMapping.map(c => c.name));
2338
+ // Use cache if columns haven't changed
2339
+ if (this._lastColumnsCodeMappingHash === columnsHash && this._displayedColumnsCache.length > 0) {
2340
+ this.displayedColumns = [...this._displayedColumnsCache];
2341
+ }
2342
+ else {
2343
+ // Update cache
2344
+ this.updateColumnMappingCache();
2345
+ this._lastColumnsCodeMappingHash = columnsHash;
2346
+ if (this.defaultDisplayedColumns && this.defaultDisplayedColumns.length) {
2347
+ this.displayedColumns = this.defaultDisplayedColumns.filter(c => this._columnMappingCache.has(c));
2348
+ }
2349
+ else {
2350
+ this.displayedColumns = this.columnsCodeMapping.map(c => c?.columnDef || c.name);
2351
+ }
2352
+ // Cache the result before adding selection/drag columns
2353
+ this._displayedColumnsCache = [...this.displayedColumns];
2354
+ }
2355
+ }
2356
+ // Add selection and drag columns (these are dynamic and shouldn't be cached)
2357
+ const finalColumns = [...this.displayedColumns];
2358
+ if (this.enableRowsSelection) {
2359
+ finalColumns.unshift('Select');
2360
+ }
2361
+ if (this.enableDragNDrop) {
2362
+ finalColumns.unshift('drag');
2363
+ }
2364
+ console.log(`=== handleDisplayedColumns :: ${msg} :: finalColumns ===`, finalColumns);
2365
+ this.displayedColumns = finalColumns;
2366
+ this.displayedColumnsChange.emit(this.displayedColumns);
2367
+ }
2368
+ updateColumnMappingCache() {
2369
+ this._columnMappingCache.clear();
2370
+ this.columnsCodeMapping.forEach(column => {
2371
+ this._columnMappingCache.set(column.name, column);
2372
+ });
2373
+ }
2374
+ // TrackBy functions for optimal rendering performance
2375
+ trackByBreadcrumb(index, breadcrumb) {
2376
+ return breadcrumb.url + breadcrumb.name || index.toString();
2377
+ }
2378
+ trackByFilterValue(index, filterValue) {
2379
+ return `${filterValue.formControlName}_${filterValue.valueKey}_${filterValue.value}`;
2380
+ }
2381
+ trackByAutoColumn(index, column) {
2382
+ return column.name + (column.serverKeyCode || '');
2383
+ }
2384
+ trackByTemplateColumn(index, column) {
2385
+ return column.name + (column.serverKeyCode || '');
2386
+ }
2387
+ trackByTableRow(index, row) {
2388
+ return row.id || row[this.selectedRowKey] || index;
2389
+ }
2390
+ // Helper method to get consistent row identifier for expansion tracking
2391
+ getRowIdentifier(row) {
2392
+ return CollectionHelper.getRowIdentifier(row, 'id', this.selectedRowKey);
2393
+ }
2394
+ // Helper method to check if a row is expanded (non-mutating)
2395
+ isRowExpanded(row) {
2396
+ if (!this.isExpansion)
2397
+ return false;
2398
+ const rowId = this.getRowIdentifier(row);
2399
+ return this.expandedRowIds.has(rowId);
2400
+ }
2401
+ // Helper method to check if a row is expanded (non-mutating)
2402
+ isRowExpandedForMobileResponsive(row) {
2403
+ if (!this.isExpansionForMobileResponsive)
2404
+ return false;
2405
+ const rowId = this.getRowIdentifier(row);
2406
+ return this.expandedRowIdsForMobileResponsive.has(rowId);
2407
+ }
2408
+ // Clear background cache when data changes to ensure fresh calculations
2409
+ clearRowBackgroundCache() {
2410
+ this.computedRowBackgrounds.clear();
2411
+ }
2412
+ // Compute all row backgrounds when data changes (runs once per data load)
2413
+ computeAllRowBackgrounds() {
2414
+ // ✅ FIX: Always clear the cache first to ensure fresh computation
2415
+ this.computedRowBackgrounds.clear();
2416
+ // ✅ FIX: Safely check if we have data and a background function
2417
+ if (!this.dataSource?.apiSubject?.value ||
2418
+ !Array.isArray(this.dataSource.apiSubject.value) ||
2419
+ !this.rowsConfig.backgroundApplyFunction) {
2420
+ return;
2421
+ }
2422
+ // ✅ FIX: Only compute backgrounds if we have actual data
2423
+ if (this.dataSource.apiSubject.value.length === 0) {
2424
+ return;
2425
+ }
2426
+ this.dataSource.apiSubject.value.forEach((row) => {
2427
+ if (!row)
2428
+ return; // Skip null/undefined rows
2429
+ const rowId = row?.id || row?.[this.selectedRowKey] || JSON.stringify(row);
2430
+ try {
2431
+ const background = this.rowsConfig.backgroundApplyFunction(row);
2432
+ this.computedRowBackgrounds.set(rowId, background);
2433
+ }
2434
+ catch (error) {
2435
+ console.warn('Error computing row background:', error);
2436
+ this.computedRowBackgrounds.set(rowId, null);
2437
+ }
2438
+ });
2439
+ }
2440
+ handleSortingChanges(ch) {
2441
+ this.sortObj = { sortOrder: ch.direction, sortBy: this.columnsCodeMapping.find(c => c.name === ch.active)?.serverKeyCode };
2442
+ this.sortFromQueryParams.sortBy = this.sortObj.sortBy;
2443
+ this.sortFromQueryParams.sortOrder = this.sortObj.sortOrder;
2444
+ this.resetFlag = true;
2445
+ this.getList();
2446
+ }
2447
+ getHomeUrl() {
2448
+ this.homeUrl = UrlHelper.getHomeUrl();
2449
+ }
2450
+ getNestedValue(obj, path) {
2451
+ return CollectionHelper.getNestedProperty(obj, path);
2452
+ }
2453
+ /** Returns the custom format string for a column type, or undefined if not set (uses pipe defaults). */
2454
+ getColumnFormat(columnType) {
2455
+ return this.columnValueTypeFormats[columnType];
2456
+ }
2457
+ groupByFormControlAttributes(data) {
2458
+ return FilterDisplayHelper.groupByFormControlAttributes(data);
2459
+ }
2460
+ updateSelectedFilterValues(values) {
2461
+ let currentFormControlName;
2462
+ if (Array.isArray(values)) {
2463
+ currentFormControlName = values[0]?.formControlName;
2464
+ }
2465
+ else {
2466
+ currentFormControlName = values?.formControlName;
2467
+ }
2468
+ const result = FilterDisplayHelper.updateSelectedFilterValues(this.selectedFilterValues, values, currentFormControlName);
2469
+ this.selectedFilterValues = result.selectedFilterValues;
2470
+ this.selectedFilterGroupedValues = result.selectedFilterGroupedValues;
2471
+ this.displayAfterFilterRemoved = true;
2472
+ this.getFinalSelectedFilterValuesToDisplay();
2473
+ }
2474
+ getFinalSelectedFilterValuesToDisplay() {
2475
+ this.finalSelectedFilterValuesToDisplay = FilterDisplayHelper.getValuesForDisplay(this.selectedFilterValues, this.filterFromQueryParams);
2476
+ }
2477
+ removeParticularFilter(f) {
2478
+ let val = this.filterFormGroup.get(f.formControlName)?.value;
2479
+ if (Array.isArray(val)) {
2480
+ val = val.filter(v => v != f.value);
2481
+ this.filterFormGroup.get(f.formControlName)?.patchValue(val);
2482
+ }
2483
+ else {
2484
+ this.filterFormGroup.get(f.formControlName)?.reset();
2485
+ }
2486
+ this.selectedFilterValues = FilterDisplayHelper.removeFilterValue(this.selectedFilterValues, f);
2487
+ this.displayAfterFilterRemoved = true;
2488
+ this.timeoutManager.createTimeout(() => {
2489
+ this.filterRecords();
2490
+ }, 500);
2491
+ }
2492
+ filterRecords() {
2493
+ this.filterApplied = true;
2494
+ this.resetFlag = true;
2495
+ // Clear computed backgrounds before loading filtered data
2496
+ this.clearRowBackgroundCache();
2497
+ this.timeoutManager.createTimeout(() => {
2498
+ this.getList(true);
2499
+ this.isShowFilter = false;
2500
+ }, 500);
2501
+ }
2502
+ resetFilters() {
2503
+ this.filterApplied = false;
2504
+ // Clear computed backgrounds before reset
2505
+ this.clearRowBackgroundCache();
2506
+ this.timeoutManager.createTimeout(() => {
2507
+ this.resetFlag = true;
2508
+ this.filterFromQueryParams = {};
2509
+ this.sortFromQueryParams = {};
2510
+ this.selectedFilterGroupedValues = [];
2511
+ this.selectedFilterValues = [];
2512
+ this.getList();
2513
+ }, 250);
2514
+ }
2515
+ getList(forceFromObject = false) {
2516
+ // Cancel any previous request to prevent race conditions
2517
+ this._currentRequestSubject.next();
2518
+ this.isAllExpanded = false;
2519
+ // Clear expansion state when loading new data to avoid stale expansion state
2520
+ CollectionHelper.clearSet(this.expandedRowIds);
2521
+ CollectionHelper.clearSet(this.expandedRowIdsForMobileResponsive);
2522
+ // ✅ FIX: Clear row background cache before loading new data to prevent stale computed backgrounds
2523
+ this.clearRowBackgroundCache();
2524
+ const filterFormData = this.filterFormGroup?.value;
2525
+ this.filterHasNonEmptyValue = ValidationHelper.hasFormData(filterFormData);
2526
+ // Build query string using helper
2527
+ const qs = QueryParamsHelper.buildQueryString(filterFormData, this.sortFromQueryParams, this.resetFlag ? 0 : this.pageIndex, this.pageSize, this.search);
2528
+ if (this.resetFlag) {
2529
+ this.pageIndex = 0;
2530
+ }
2531
+ if (this._paginator) {
2532
+ this._paginator.pageIndex = this.pageIndex;
2533
+ this._paginator.pageSize = this.pageSize;
2534
+ }
2535
+ // Update URL if needed
2536
+ const baseUrl = UrlHelper.getBaseUrl(this.router);
2537
+ const genUrl = UrlHelper.buildUrl(baseUrl, qs);
2538
+ if (this.keepFilterInUrl && UrlHelper.hasUrlChanged(genUrl)) {
2539
+ UrlHelper.updateUrl(this.location, baseUrl, qs.toString());
2540
+ this.filterFromQueryParams = QueryParamsHelper.parseQueryParams(window.location.href);
2541
+ }
2542
+ // Load data with race condition protection
2543
+ this.dataSource.loadWithCancellation(this.loadDataApiBaseUrl, this.pageIndex, this.pageSize, this.search, filterFormData, // Pass original form data - datasource will handle conversions
2544
+ this.sortObj, this._currentRequestSubject);
2545
+ this.getFinalSelectedFilterValuesToDisplay();
2546
+ this.resetFlag = false;
2547
+ }
2548
+ onPaginationChanges() {
2549
+ // Read both new values up front. Changing the page size on a non-first page
2550
+ // makes mat-paginator recompute pageIndex AND pageSize in a single event;
2551
+ // handling them in two separate getList() calls used to fail because the
2552
+ // first call writes the (still old) pageSize back onto the paginator
2553
+ // (see getList), making the second comparison false and dropping the new
2554
+ // page size. Capture both, apply both, and load once.
2555
+ const newPageIndex = this._paginator.pageIndex;
2556
+ const newPageSize = this._paginator.pageSize;
2557
+ const pageIndexChanged = this.pageIndex != newPageIndex;
2558
+ const pageSizeChanged = this.pageSize != newPageSize;
2559
+ if (pageIndexChanged || pageSizeChanged) {
2560
+ this.pageIndex = newPageIndex;
2561
+ this.pageSize = newPageSize;
2562
+ // Clear computed backgrounds before loading new page data
2563
+ this.clearRowBackgroundCache();
2564
+ this.getList();
2565
+ if (pageIndexChanged) {
2566
+ this.pageIndexChange.emit(this.pageIndex);
2567
+ }
2568
+ if (pageSizeChanged) {
2569
+ this.pageSizeChange.emit(this.pageSize);
2570
+ setToLocalStorageWithExpiry('user_pagination_page_size', this.pageSize, 1000 * 60 * 60 * 24 * 15);
2571
+ }
2572
+ }
2573
+ }
2574
+ onSetSelectedTemplate(data) {
2575
+ console.log("=== onSetSelectedTemplate ===", data);
2576
+ // this.selectedTemplate = data;
2577
+ }
2578
+ onChangeDisplayColumns(columns) {
2579
+ console.log("=== onChangeDisplayColumns ===", columns);
2580
+ this.defaultDisplayedColumns = columns;
2581
+ this.handleDisplayedColumns('onChangeDisplayColumns');
2582
+ }
2583
+ onChangeFromStartColumnNumber(columnNumber) {
2584
+ this.startStickyColumnCount = columnNumber;
2585
+ }
2586
+ onChangeFromEndColumnNumber(columnNumber) {
2587
+ this.endStickyColumnCount = columnNumber;
2588
+ }
2589
+ goToUrl(url) {
2590
+ UrlHelper.safeNavigate(this.router, url);
2591
+ }
2592
+ toggleSelection(status, row) {
2593
+ // ✅ Add null guards to prevent crashes
2594
+ if (!row || !ValidationHelper.hasRowKey(row, this.selectedRowKey)) {
2595
+ return;
2596
+ }
2597
+ if (this.onlySingleSelection && status.checked) {
2598
+ this.selection.clear();
2599
+ }
2600
+ const found = this.selection?.selected.find((el) => {
2601
+ return el[this.selectedRowKey] == row[this.selectedRowKey];
2602
+ });
2603
+ if (found) {
2604
+ this.selection?.deselect(found);
2605
+ }
2606
+ else {
2607
+ this.selection?.select(row);
2608
+ }
2609
+ // this.selection.toggle(row);
2610
+ this.selectedRows = this.selection.selected;
2611
+ this.selectedRowsChange.emit(this.selectedRows);
2612
+ this.checkAllRowsSelected();
2613
+ }
2614
+ checkAllRowsSelected() {
2615
+ // ✅ Add comprehensive null guards to prevent crashes
2616
+ if (!this.dataSource?.apiSubject?.value || !Array.isArray(this.dataSource.apiSubject.value)) {
2617
+ this.isAllRowsSelected = false;
2618
+ this.allRowsSelectedChange.emit(this.isAllRowsSelected);
2619
+ return;
2620
+ }
2621
+ this.isAllRowsSelected = this.dataSource.apiSubject.value.every((row) => {
2622
+ const selected = this.selection?.selected.find(selection => selection[this.selectedRowKey] == row[this.selectedRowKey]);
2623
+ return !!selected;
2624
+ });
2625
+ // this.isAllRowsSelected = (this.selection.selected.length >= this.dataSource.apiSubject.value.length);
2626
+ this.allRowsSelectedChange.emit(this.isAllRowsSelected);
2627
+ }
2628
+ toggleAllRows() {
2629
+ // ✅ Add comprehensive null guards
2630
+ if (!this.dataSource?.apiSubject?.value || !Array.isArray(this.dataSource.apiSubject.value)) {
2631
+ return;
2632
+ }
2633
+ if (this.isAllRowsSelected) {
2634
+ this.selection.clear();
2635
+ }
2636
+ else {
2637
+ this.dataSource.apiSubject.value.forEach(row => {
2638
+ // ✅ Validate each row before selecting
2639
+ if (row && ValidationHelper.hasRowKey(row, this.selectedRowKey)) {
2640
+ if (!this.isChecked(row)) {
2641
+ this.selection.select(row);
2642
+ }
2643
+ }
2644
+ });
2645
+ }
2646
+ this.selectedRows = this.selection.selected;
2647
+ this.selectedRowsChange.emit(this.selectedRows);
2648
+ this.checkAllRowsSelected();
2649
+ }
2650
+ stopPropagation($event) {
2651
+ $event.stopPropagation();
2652
+ }
2653
+ isChecked(row) {
2654
+ // ✅ Add comprehensive null guards
2655
+ if (!row ||
2656
+ !ValidationHelper.hasRowKey(row, this.selectedRowKey) ||
2657
+ !this.selectedIds) {
2658
+ return false;
2659
+ }
2660
+ return this.selectedIds.has(row[this.selectedRowKey]);
2661
+ }
2662
+ getQueryParams(url) {
2663
+ return QueryParamsHelper.parseQueryParams(url);
2664
+ }
2665
+ isStickyStart(columnName) {
2666
+ const index = this.displayedColumns.indexOf(columnName);
2667
+ return index !== -1 && index < this.startStickyColumnCount;
2668
+ }
2669
+ isStickyEnd(columnName) {
2670
+ const index = this.displayedColumns.indexOf(columnName);
2671
+ if (index === -1)
2672
+ return false;
2673
+ return index >= this.displayedColumns.length - this.endStickyColumnCount;
2674
+ }
2675
+ getColumnClasses(column) {
2676
+ // Check if alignment is explicitly specified
2677
+ if (column.align) {
2678
+ return {
2679
+ 'text-right': column.align === 'right',
2680
+ 'text-left': column.align === 'left',
2681
+ 'text-center': column.align === 'center'
2682
+ };
2683
+ }
2684
+ else {
2685
+ // Default alignment based on column type
2686
+ switch (column.type) {
2687
+ case 'money':
2688
+ case 'quantity':
2689
+ return { 'text-right': true };
2690
+ case 'number':
2691
+ return { 'text-center': true };
2692
+ default:
2693
+ return {};
2694
+ }
2695
+ }
2696
+ }
2697
+ // Optimized getRowBackground - simple O(1) lookup
2698
+ getRowBackground(row) {
2699
+ // Early return if no background function is provided
2700
+ if (!this.rowsConfig.backgroundApplyFunction) {
2701
+ return null;
2702
+ }
2703
+ const rowId = row?.id || row?.[this.selectedRowKey] || JSON.stringify(row);
2704
+ // If not computed yet, compute on-demand (fallback)
2705
+ if (!this.computedRowBackgrounds.has(rowId)) {
2706
+ try {
2707
+ const background = this.rowsConfig.backgroundApplyFunction(row);
2708
+ this.computedRowBackgrounds.set(rowId, background);
2709
+ return background;
2710
+ }
2711
+ catch (error) {
2712
+ console.warn('Error computing row background:', error);
2713
+ return null;
2714
+ }
2715
+ }
2716
+ return this.computedRowBackgrounds.get(rowId) || null;
2717
+ }
2718
+ drop(event) {
2719
+ // ✅ Add null guards to prevent crashes
2720
+ if (!this.dataSource?.apiSubject?.value || !Array.isArray(this.dataSource.apiSubject.value)) {
2721
+ return;
2722
+ }
2723
+ // Ignore if the item was dropped at the same index
2724
+ if (event.previousIndex === event.currentIndex) {
2725
+ return;
2726
+ }
2727
+ // Access current data from apiSubject
2728
+ const currentData = [...this.dataSource.apiSubject.value];
2729
+ if (!currentData || currentData.length === 0) {
2730
+ return;
2731
+ }
2732
+ // Rearrange items based on the drop event
2733
+ moveItemInArray(currentData, event.previousIndex, event.currentIndex);
2734
+ // Update the apiSubject with reordered data
2735
+ this.dataSource.apiSubject.next(currentData);
2736
+ // We need to emit this also
2737
+ this.listDataSequenceChange.emit(currentData);
2738
+ }
2739
+ handleButtonClick(config) {
2740
+ UrlHelper.handleButtonClick(this.router, config);
2741
+ }
2742
+ handleSecondButtonClick(config) {
2743
+ UrlHelper.handleSecondaryButtonClick(this.router, config);
2744
+ }
2745
+ setSelectedRows() {
2746
+ // ✅ Add null guards to prevent crashes
2747
+ if (!this.dataSource?.apiSubject?.value ||
2748
+ !Array.isArray(this.dataSource.apiSubject.value) ||
2749
+ !this.selectedRowIds) {
2750
+ this.selection.clear();
2751
+ this.selectedRows = [];
2752
+ this.selectedRowsChange.emit(this.selectedRows);
2753
+ return;
2754
+ }
2755
+ this.selection.clear();
2756
+ // ✅ FIX: Convert array to Set for O(1) lookup instead of O(n) indexOf
2757
+ const selectedIdsSet = new Set(this.selectedRowIds);
2758
+ this.dataSource.apiSubject.value.forEach(row => {
2759
+ if (row &&
2760
+ ValidationHelper.hasRowKey(row, this.selectedRowKey) &&
2761
+ selectedIdsSet.has(row[this.selectedRowKey])) {
2762
+ this.selection.select(row);
2763
+ }
2764
+ });
2765
+ this.selectedRows = this.selection.selected;
2766
+ this.selectedRowsChange.emit(this.selectedRows);
2767
+ this.checkAllRowsSelected();
2768
+ }
2769
+ resetSelectedRows() {
2770
+ this.isAllRowsSelected = false;
2771
+ this.selection.clear();
2772
+ this.selectedRows = this.selection.selected;
2773
+ this.selectedRowsChange.emit(this.selectedRows);
2774
+ }
2775
+ /** Toggles the expanded state of an element. */
2776
+ toggleExpand(element) {
2777
+ if (!this.isExpansion || !element) {
2778
+ return;
2779
+ }
2780
+ const rowId = this.getRowIdentifier(element);
2781
+ if (this.expandedRowIds.has(rowId)) {
2782
+ this.expandedRowIds.delete(rowId);
2783
+ }
2784
+ else {
2785
+ this.expandedRowIds.add(rowId);
2786
+ }
2787
+ }
2788
+ expandAllRow() {
2789
+ if (!this.isExpansion || !this.dataSource?.apiSubject?.value) {
2790
+ return;
2791
+ }
2792
+ this.isAllExpanded = !this.isAllExpanded;
2793
+ if (this.isAllExpanded) {
2794
+ // Add all row IDs to expanded set
2795
+ this.dataSource.apiSubject.value.forEach(row => {
2796
+ const rowId = this.getRowIdentifier(row);
2797
+ this.expandedRowIds.add(rowId);
2798
+ });
2799
+ }
2800
+ else {
2801
+ // Clear all expanded rows
2802
+ this.expandedRowIds.clear();
2803
+ }
2804
+ }
2805
+ /** Toggles the expanded state of an element. */
2806
+ toggleExpandForMobileResponsive(element) {
2807
+ if (!this.isExpansionForMobileResponsive || !element) {
2808
+ return;
2809
+ }
2810
+ const rowId = this.getRowIdentifier(element);
2811
+ if (this.expandedRowIdsForMobileResponsive.has(rowId)) {
2812
+ this.expandedRowIdsForMobileResponsive.delete(rowId);
2813
+ }
2814
+ else {
2815
+ this.expandedRowIdsForMobileResponsive.add(rowId);
2816
+ }
2817
+ }
2818
+ expandAllRowForMobileResponsive() {
2819
+ if (!this.isExpansionForMobileResponsive || !this.dataSource?.apiSubject?.value) {
2820
+ return;
2821
+ }
2822
+ this.isAllExpandedForMobileResponsive = !this.isAllExpandedForMobileResponsive;
2823
+ if (this.isAllExpandedForMobileResponsive) {
2824
+ // Add all row IDs to expanded set
2825
+ this.dataSource.apiSubject.value.forEach(row => {
2826
+ const rowId = this.getRowIdentifier(row);
2827
+ this.expandedRowIdsForMobileResponsive.add(rowId);
2828
+ });
2829
+ }
2830
+ else {
2831
+ // Clear all expanded rows
2832
+ this.expandedRowIdsForMobileResponsive.clear();
2833
+ }
2834
+ }
2835
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableComponent, deps: [{ token: i1$1.MatDialog }, { token: ApiService }, { token: i3$1.ActivatedRoute }, { token: i3$1.Router }, { token: i4.Location }, { token: i5.BreakpointObserver }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
2836
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: AngularSmartDataTableComponent, isStandalone: false, selector: "angular-smart-data-table", inputs: { columnCustomizationUrlConfig: "columnCustomizationUrlConfig", t: "t", componentName: "componentName", mainTitle: "mainTitle", searchPlaceholder: "searchPlaceholder", breadcrumbs: "breadcrumbs", hideHeader: "hideHeader", hideTableHeader: "hideTableHeader", hidePaginator: "hidePaginator", keepFilterInUrl: "keepFilterInUrl", disableBorderedView: "disableBorderedView", displayColumnsSelectionButton: "displayColumnsSelectionButton", loadDataApiBaseUrl: "loadDataApiBaseUrl", startStickyColumnCount: "startStickyColumnCount", endStickyColumnCount: "endStickyColumnCount", isSearchFieldMobileResponsive: "isSearchFieldMobileResponsive", isMobileResponsiveTable: "isMobileResponsiveTable", loaderPosition: "loaderPosition", dataNotFoundConfig: "dataNotFoundConfig", showFilterButtonSection: "showFilterButtonSection", columnValueTypeFormats: "columnValueTypeFormats", columnsCodeMapping: "columnsCodeMapping", defaultDisplayedColumns: "defaultDisplayedColumns", defaultSortObj: "defaultSortObj", loadingSpinnerDiameter: "loadingSpinnerDiameter", pageSizeOptions: "pageSizeOptions", pageSize: "pageSize", useGlobalPageSize: "useGlobalPageSize", pageIndex: "pageIndex", filterFormGroup: "filterFormGroup", rowsConfig: "rowsConfig", hasSelectedAllRows: "hasSelectedAllRows", enableRowsSelection: "enableRowsSelection", enableAllRowsSelection: "enableAllRowsSelection", onlySingleSelection: "onlySingleSelection", selectedRowIds: "selectedRowIds", selectedRowKey: "selectedRowKey", selectedRows: "selectedRows", enableDragNDrop: "enableDragNDrop", isExpansion: "isExpansion", isExpandedRow: "isExpandedRow", expandedTemplate: "expandedTemplate", isExpansionForMobileResponsive: "isExpansionForMobileResponsive", isExpandedRowForMobileResponsive: "isExpandedRowForMobileResponsive", expandedTemplateForMobileResponsive: "expandedTemplateForMobileResponsive", headerTemplateForEachRowForMobileResponsive: "headerTemplateForEachRowForMobileResponsive" }, outputs: { displayedColumnsChange: "displayedColumnsChange", sortObjChange: "sortObjChange", pageSizeChange: "pageSizeChange", pageIndexChange: "pageIndexChange", onDataLoaded: "onDataLoaded", onSetExtraData: "onSetExtraData", onSetTotal: "onSetTotal", selectedRowsChange: "selectedRowsChange", allRowsSelectedChange: "allRowsSelectedChange", listDataSequenceChange: "listDataSequenceChange" }, providers: [CdkColumnDef], viewQueries: [{ propertyName: "table", first: true, predicate: MatTable, descendants: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section [class.angular-page]=\"!hideHeader\">\n <div class=\"angular-page-header\" *ngIf=\"!hideHeader\">\n <nav aria-label=\"angular-breadcrumb\">\n <ol class=\"angular-breadcrumb\">\n <li class=\"angular-breadcrumb-item\"><a href=\"javascript:;\" [routerLink]=\"homeUrl\">{{t?.home}}</a></li>\n @for(breadcrumb of breadcrumbs; track trackByBreadcrumb($index, breadcrumb)) {\n <li class=\"angular-breadcrumb-item\" *ngIf=\"breadcrumb?.url\">\n <a href=\"javascript:;\" (click)=\"goToUrl(breadcrumb.url)\">{{breadcrumb?.name}}</a>\n </li>\n }\n <li class=\"angular-breadcrumb-item active\">\n {{mainTitle}}\n </li>\n </ol>\n </nav>\n <ng-content select=\"[slot='top-buttons-section']\"></ng-content>\n </div>\n <h1 class=\"angular-page-title\" *ngIf=\"!hideHeader\">{{mainTitle}}</h1>\n <div class=\"angular-page-body\">\n <div class=\"angular-page-body-content\">\n\n @if(initialLoading){\n <div class=\"angular-d-flex angular-justify-content-center pb-2 pt-7\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"60\"></mat-progress-spinner>\n </div>\n } @else {\n\n @if ((dataSource?.totalDataLength$ | async) || (dataSource?.loading$ | async) || search ||\n filterHasNonEmptyValue || showFilterButtonSection || displayAfterFilterRemoved) {\n <div class=\"angular-table-container\">\n @if(!hideTableHeader){\n <div class=\"angular-table-container-header\">\n <ul class=\"angular-inline-group\">\n <li class=\"angular-inline-group-item\">\n <angular-columns-btn [columnCustomizationUrlConfig]=\"columnCustomizationUrlConfig\" [t]=\"t\"\n [componentName]=\"componentName\" [(selectedTemplate)]=\"selectedTemplate\" [defaultColumns]=\"defaultColumns\" [columns]=\"columns\"\n (selectedTemplateChange)=\"onSetSelectedTemplate($event)\"\n (displayedColumnsChange)=\"onChangeDisplayColumns($event)\"\n (fromStartColumnNumberChange)=\"onChangeFromStartColumnNumber($event)\"\n (fromEndColumnNumberChange)=\"onChangeFromEndColumnNumber($event)\"></angular-columns-btn>\n </li>\n <ng-content select=\"[slot='filter-button-section']\"></ng-content>\n </ul>\n <div class=\"flex items-center\">\n <ul class=\"angular-inline-group\">\n <ng-content select=\"[slot='filter-right-button-section']\"></ng-content>\n </ul>\n @if((!isMobile || !isSearchFieldMobileResponsive) && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field ml-3 angular-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 angular-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n </div>\n </div>\n }\n\n @if (filterFormGroup) {\n\n <ng-content select=\"[slot='filter-form-section']\"></ng-content>\n\n @if(finalSelectedFilterValuesToDisplay.length && filterApplied) {\n <div class=\"flex gap-3 mb-3 filter-applied-section md-hide-scrollbar\">\n @for(v of finalSelectedFilterValuesToDisplay; track trackByFilterValue($index, v)) {\n @if (v) {\n <span class=\"angular-filter-badge\" style=\"white-space: nowrap;\">\n @if(v.labelKey && v.labelKey != '' && (v.valueKey || v.value)) {\n <span class=\"font-semibold\"> {{v.labelKey }} </span>\n }\n @if(v.valueKey) {\n {{v.valueKey }}\n } @else {\n {{v.value }}\n }\n <span class=\"material-icons angular-curser-pointer\"\n (click)=\"removeParticularFilter(v)\">cancel</span>\n </span>\n }\n }\n </div>\n }\n }\n\n @if((isMobile && isSearchFieldMobileResponsive) && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field mb-3 angular-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 angular-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n\n \n @if(loaderPosition == 'top'){\n @if(dataSource?.loading$ | async){\n <div class=\"angular-d-flex angular-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n <div class=\"angular-table-container-body\">\n <div class=\"angular-table-wrapper\" [angularSmartDataTableScrolling]=\"true\">\n\n @if ( isMobileResponsiveTable == false || (isMobileResponsiveTable == true && isMobile == false)) {\n <!--Table Here-->\n <table mat-table matSort [dataSource]=\"dataSource\" class=\"angular-table\" [class.angular-table-bordered]=\"disableBorderedView == false\" cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListLockAxis]=\"'y'\" multiTemplateDataRows>\n\n @if (enableRowsSelection) {\n <ng-container matColumnDef=\"Select\">\n <th mat-header-cell *matHeaderCellDef>\n @if (enableAllRowsSelection) {\n <mat-checkbox color=\"primary\" (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"isAllRowsSelected || hasSelectedAllRows\"\n [indeterminate]=\"selection.hasValue() && !isAllRowsSelected\">\n </mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox color=\"primary\" (click)=\"stopPropagation($event)\" (change)=\"$event ? toggleSelection($event, row) : null\" [checked]=\"isChecked(row) || hasSelectedAllRows\"></mat-checkbox>\n </td>\n </ng-container>\n }\n\n @for(column of autoRenderColumns; track trackByAutoColumn($index, column); let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"i > (autoRenderColumns?.length - endStickyColumnCount)\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px;\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell mat-sort-header *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n \n\n @if(column.type == 'date'){\n <td mat-cell *matCellDef=\"let element\" class=\"1al-{{column.align}} 1ty-{{column.type}}\" >\n @if(column.linkFn) {\n <a [routerLink]=\"column.linkFn(element)\" class=\"angular-a\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDate : getColumnFormat(column.type)) : ''}}\n </a>\n } @else {\n <p [class.angular-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDate : getColumnFormat(column.type)) : ''}}\n </p>\n }\n </td>\n } @else if(column.type == 'date-time'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n @if(column.linkFn) {\n <a [routerLink]=\"column.linkFn(element)\" class=\"angular-a\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDateTime : getColumnFormat(column.type)) : ''}}\n </a>\n } @else {\n <p [class.angular-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDateTime : getColumnFormat(column.type)) : ''}}\n </p>\n }\n </td>\n } @else if(column.type == 'date-time-with-seconds'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n @if(column.linkFn) {\n <a [routerLink]=\"column.linkFn(element)\" class=\"angular-a\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDateTimeWithSeconds : getColumnFormat(column.type)) : ''}}\n </a>\n } @else {\n <p [class.angular-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDateTimeWithSeconds : getColumnFormat(column.type)) : ''}}\n </p>\n }\n </td>\n } @else {\n <td mat-cell *matCellDef=\"let element\" class=\"3al-{{column.align}} 3ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n @if(column.linkFn) {\n <a [routerLink]=\"column.linkFn(element)\" class=\"angular-a\">\n @if (column.type == 'quantity') {\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | number : (getColumnFormat(column.type) || '1.4-4')) : '-' }}\n } @else if (column.type == 'money') {\n {{ column.valueKey && (getNestedValue(element, column.valueKey)) | angularCurrency : getColumnFormat(column.type) }}\n } @else {\n {{ column.valueKey && getNestedValue(element, column.valueKey) }}\n }\n </a>\n } @else {\n <p [class.angular-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n @if (column.type == 'quantity') {\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | number : (getColumnFormat(column.type) || '1.4-4')) : '-' }}\n } @else if (column.type == 'money') {\n {{ column.valueKey && (getNestedValue(element, column.valueKey)) | angularCurrency : getColumnFormat(column.type) }}\n } @else {\n {{ column.valueKey && getNestedValue(element, column.valueKey) }}\n }\n </p>\n }\n </td>\n }\n </ng-container>\n\n }\n\n\n @for(column of templateRenderColumns; track trackByTemplateColumn($index, column); let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"l\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px; cursor: pointer;\" (click)=\"expandAllRow()\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n <td mat-cell *matCellDef=\"let element\" class=\"4al-{{column.align}} 4ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <ng-container *ngIf=\"column.template as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colDef: column, colData: element }\"></ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n\n <!--Drag Column Def Start-->\n <ng-container [matColumnDef]=\"'drag'\" >\n <th mat-header-cell *matHeaderCellDef>\n --\n </th>\n <td mat-cell *matCellDef=\"let element\" class=\"5al-drag 5ty-drag\">\n <mat-icon cdkDragHandle class=\"angular-curser-pointer\" style=\"color: rgba(0, 0, 0, 0.54); font-size: 19px; width: 19px; height: 19px;\">drag_indicator</mat-icon>\n </td>\n </ng-container>\n <!--Drag Column Def End-->\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"displayedColumns.length\" [style.border-bottom-width]=\"isRowExpanded(element) ? '1px' : '0px'\" style=\"padding: 0px !important;\">\n <div class=\"angular-element-detail-wrapper\" [class.angular-element-detail-wrapper-expanded]=\"isRowExpanded(element)\">\n <ng-container *ngIf=\"expandedTemplate as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\" [attr.colspan]=\"displayedColumns.length\">\n <div class=\"angular-data-not-found\">\n @if(dataNotFoundConfig.iconUrl) {\n <img [src]=\"dataNotFoundConfig.iconUrl\" alt=\"No data found\" />\n } @else {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n }\n <h5 class=\"angular-h5\">{{dataNotFoundConfig.title}}</h5>\n </div>\n </td>\n </tr>\n\n <!-- Apply Drag and Drop to tbody -->\n @if(enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.angular-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\" cdkDrag></tr>\n }\n\n @if(!enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.angular-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\"></tr>\n } \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"angular-detail-row\"></tr>\n </table>\n <!--Table End-->\n }\n @else {\n <!-- Mobile Card View -->\n @if (dataSource?.apiSubject | async; as rows) {\n <table class=\"angular-table angular-mobile-responsive-table\" [class.angular-table-bordered]=\"disableBorderedView == false\">\n <tbody>\n @for (element of rows; track trackByTableRow($index, element)) {\n <tr [ngStyle]=\"{'background-color': getRowBackground(element) || 'inherit'}\" [class.angular-curser-pointer]=\"isExpandedRowForMobileResponsive\" (click)=\"(isExpansionForMobileResponsive && isExpandedRowForMobileResponsive) ? toggleExpandForMobileResponsive(element) : null\">\n <td>\n <div class=\"angular-table-responsive-table-wrapper\">\n <div class=\"angular-table-responsive-table-header-wrapper\">\n @if (enableRowsSelection) {\n <div class=\"angular-table-responsive-table-header-wrapper-item\">\n <mat-checkbox color=\"primary\" (click)=\"stopPropagation($event)\" (change)=\"$event ? toggleSelection($event, element) : null\" [checked]=\"isChecked(element) || hasSelectedAllRows\"></mat-checkbox>\n </div>\n }\n <div class=\"angular-table-responsive-table-header-wrapper-item\" style=\"flex: 1 1 0%;\">\n <ng-container *ngIf=\"headerTemplateForEachRowForMobileResponsive as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </div>\n <div class=\"angular-table-responsive-table-content-wrapper\" [class.angular-table-responsive-table-content-wrapper-expanded]=\"isRowExpandedForMobileResponsive(element)\">\n <ng-container *ngIf=\"expandedTemplateForMobileResponsive as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n }\n }\n\n </div>\n @if(loaderPosition == 'bottom'){\n @if(dataSource?.loading$ | async){\n <div class=\"angular-d-flex angular-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n @if (!hidePaginator) {\n <div class=\"angular-table-paginator\">\n <mat-paginator [length]=\"dataSource?.totalDataLength?.value\" [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\" showFirstLastButtons></mat-paginator>\n </div>\n }\n </div>\n </div>\n } @else {\n\n @if(dataNotFoundConfig) {\n <div class=\"angular-data-not-found\">\n @if(dataNotFoundConfig.iconUrl) {\n <img [src]=\"dataNotFoundConfig.iconUrl\" alt=\"No data found\" />\n } @else {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n }\n <h5 class=\"angular-h5\">{{dataNotFoundConfig.title}}</h5>\n @if(dataNotFoundConfig.desc) {\n <p class=\"angular-p\">{{dataNotFoundConfig.desc}}</p>\n }\n @if((dataNotFoundConfig.btnUrl || dataNotFoundConfig?.btnClick) && dataNotFoundConfig.btnText) {\n <button mat-flat-button color=\"primary\" class=\"angular-text-upper\"\n (click)=\"handleButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.btnText}}\n </button>\n }\n @if((dataNotFoundConfig.secondBtnUrl || dataNotFoundConfig?.secondBtnClick) && dataNotFoundConfig.secondBtnText) {\n <button mat-stroked-button color=\"primary\" class=\"angular-text-upper\"\n (click)=\"handleSecondButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.secondBtnText}}\n </button>\n }\n </div>\n }\n\n }\n\n }\n\n </div>\n </div>\n</section>", styles: ["::ng-deep .sub-main-content{border:0px solid #f00;margin-top:56px;height:calc(100% - 56px);padding:15px;overflow:auto}.header-title{margin-top:8px;padding:7px 10px;color:#969a9c}.header-title h3{font-size:20px!important;font-weight:700}.header-menu{border:0px solid red;background:#fff;margin-top:1px;margin-bottom:0}.w-100{width:100%}.mat-mdc-table-sticky-border-elem-right{border-left:1px solid #e0e0e087}.mat-mdc-table-sticky-border-elem-left{border-right:1px solid #e0e0e087}.search-mat-form-field{width:100%}.filter-applied-section{overflow:auto}.angular-detail-row{height:0!important}.angular-element-detail-wrapper{overflow:hidden;max-height:0;transition:max-height 225ms ease}.angular-element-detail-wrapper-expanded{max-height:500px}.angular-table-bordered{border-collapse:collapse;width:100%}.angular-table-bordered th,.angular-table-bordered td{border-left:1px solid #e0e0e0}.angular-table-bordered th:first-child,.angular-table-bordered td:first-child{border-left:0px solid #e0e0e0}.angular-table-bordered .bg-unset{background-color:unset!important}.angular-table-responsive-table-wrapper{width:100%;display:flex;flex-direction:column}.angular-table-responsive-table-header-wrapper{width:100%;display:flex;flex-direction:row;gap:10px;align-items:center}.angular-table-responsive-table-content-wrapper{width:100%}@media (max-width: 575.98px){.search-mat-form-field{width:100%!important}}@media (min-width: 576px) and (max-width: 767.98px){.search-mat-form-field{width:100%!important}}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i3$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i8.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i10.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i10$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i12$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: i13$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i13$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i13$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i13$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i13$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i13$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i13$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i13$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i13$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i13$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i13$1.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "component", type: i12.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: i15.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i15.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "directive", type: i13.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i13.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i13.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: ScrollingDirective, selector: "[angularSmartDataTableScrolling]", inputs: ["angularSmartDataTableScrolling"] }, { kind: "component", type: AngularColumnsBtnComponent, selector: "angular-columns-btn", inputs: ["columnCustomizationUrlConfig", "t", "componentName", "defaultColumns", "columns", "skipTranslation", "customColumns", "selectedTemplate"], outputs: ["selectedTemplateChange", "displayedColumnsChange", "fromStartColumnNumberChange", "fromEndColumnNumberChange"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.DecimalPipe, name: "number" }, { kind: "pipe", type: AngularDatePipe, name: "angularDate" }, { kind: "pipe", type: AngularDateTimePipe, name: "angularDateTime" }, { kind: "pipe", type: AngularDateTimeWithSecondsPipe, name: "angularDateTimeWithSeconds" }, { kind: "pipe", type: AngularCurrencyPipe, name: "angularCurrency" }] });
2837
+ }
2838
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableComponent, decorators: [{
2839
+ type: Component,
2840
+ args: [{ selector: 'angular-smart-data-table', standalone: false, providers: [CdkColumnDef], template: "<section [class.angular-page]=\"!hideHeader\">\n <div class=\"angular-page-header\" *ngIf=\"!hideHeader\">\n <nav aria-label=\"angular-breadcrumb\">\n <ol class=\"angular-breadcrumb\">\n <li class=\"angular-breadcrumb-item\"><a href=\"javascript:;\" [routerLink]=\"homeUrl\">{{t?.home}}</a></li>\n @for(breadcrumb of breadcrumbs; track trackByBreadcrumb($index, breadcrumb)) {\n <li class=\"angular-breadcrumb-item\" *ngIf=\"breadcrumb?.url\">\n <a href=\"javascript:;\" (click)=\"goToUrl(breadcrumb.url)\">{{breadcrumb?.name}}</a>\n </li>\n }\n <li class=\"angular-breadcrumb-item active\">\n {{mainTitle}}\n </li>\n </ol>\n </nav>\n <ng-content select=\"[slot='top-buttons-section']\"></ng-content>\n </div>\n <h1 class=\"angular-page-title\" *ngIf=\"!hideHeader\">{{mainTitle}}</h1>\n <div class=\"angular-page-body\">\n <div class=\"angular-page-body-content\">\n\n @if(initialLoading){\n <div class=\"angular-d-flex angular-justify-content-center pb-2 pt-7\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"60\"></mat-progress-spinner>\n </div>\n } @else {\n\n @if ((dataSource?.totalDataLength$ | async) || (dataSource?.loading$ | async) || search ||\n filterHasNonEmptyValue || showFilterButtonSection || displayAfterFilterRemoved) {\n <div class=\"angular-table-container\">\n @if(!hideTableHeader){\n <div class=\"angular-table-container-header\">\n <ul class=\"angular-inline-group\">\n <li class=\"angular-inline-group-item\">\n <angular-columns-btn [columnCustomizationUrlConfig]=\"columnCustomizationUrlConfig\" [t]=\"t\"\n [componentName]=\"componentName\" [(selectedTemplate)]=\"selectedTemplate\" [defaultColumns]=\"defaultColumns\" [columns]=\"columns\"\n (selectedTemplateChange)=\"onSetSelectedTemplate($event)\"\n (displayedColumnsChange)=\"onChangeDisplayColumns($event)\"\n (fromStartColumnNumberChange)=\"onChangeFromStartColumnNumber($event)\"\n (fromEndColumnNumberChange)=\"onChangeFromEndColumnNumber($event)\"></angular-columns-btn>\n </li>\n <ng-content select=\"[slot='filter-button-section']\"></ng-content>\n </ul>\n <div class=\"flex items-center\">\n <ul class=\"angular-inline-group\">\n <ng-content select=\"[slot='filter-right-button-section']\"></ng-content>\n </ul>\n @if((!isMobile || !isSearchFieldMobileResponsive) && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field ml-3 angular-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 angular-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n </div>\n </div>\n }\n\n @if (filterFormGroup) {\n\n <ng-content select=\"[slot='filter-form-section']\"></ng-content>\n\n @if(finalSelectedFilterValuesToDisplay.length && filterApplied) {\n <div class=\"flex gap-3 mb-3 filter-applied-section md-hide-scrollbar\">\n @for(v of finalSelectedFilterValuesToDisplay; track trackByFilterValue($index, v)) {\n @if (v) {\n <span class=\"angular-filter-badge\" style=\"white-space: nowrap;\">\n @if(v.labelKey && v.labelKey != '' && (v.valueKey || v.value)) {\n <span class=\"font-semibold\"> {{v.labelKey }} </span>\n }\n @if(v.valueKey) {\n {{v.valueKey }}\n } @else {\n {{v.value }}\n }\n <span class=\"material-icons angular-curser-pointer\"\n (click)=\"removeParticularFilter(v)\">cancel</span>\n </span>\n }\n }\n </div>\n }\n }\n\n @if((isMobile && isSearchFieldMobileResponsive) && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field mb-3 angular-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 angular-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n\n \n @if(loaderPosition == 'top'){\n @if(dataSource?.loading$ | async){\n <div class=\"angular-d-flex angular-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n <div class=\"angular-table-container-body\">\n <div class=\"angular-table-wrapper\" [angularSmartDataTableScrolling]=\"true\">\n\n @if ( isMobileResponsiveTable == false || (isMobileResponsiveTable == true && isMobile == false)) {\n <!--Table Here-->\n <table mat-table matSort [dataSource]=\"dataSource\" class=\"angular-table\" [class.angular-table-bordered]=\"disableBorderedView == false\" cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListLockAxis]=\"'y'\" multiTemplateDataRows>\n\n @if (enableRowsSelection) {\n <ng-container matColumnDef=\"Select\">\n <th mat-header-cell *matHeaderCellDef>\n @if (enableAllRowsSelection) {\n <mat-checkbox color=\"primary\" (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"isAllRowsSelected || hasSelectedAllRows\"\n [indeterminate]=\"selection.hasValue() && !isAllRowsSelected\">\n </mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox color=\"primary\" (click)=\"stopPropagation($event)\" (change)=\"$event ? toggleSelection($event, row) : null\" [checked]=\"isChecked(row) || hasSelectedAllRows\"></mat-checkbox>\n </td>\n </ng-container>\n }\n\n @for(column of autoRenderColumns; track trackByAutoColumn($index, column); let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"i > (autoRenderColumns?.length - endStickyColumnCount)\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px;\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell mat-sort-header *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n \n\n @if(column.type == 'date'){\n <td mat-cell *matCellDef=\"let element\" class=\"1al-{{column.align}} 1ty-{{column.type}}\" >\n @if(column.linkFn) {\n <a [routerLink]=\"column.linkFn(element)\" class=\"angular-a\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDate : getColumnFormat(column.type)) : ''}}\n </a>\n } @else {\n <p [class.angular-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDate : getColumnFormat(column.type)) : ''}}\n </p>\n }\n </td>\n } @else if(column.type == 'date-time'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n @if(column.linkFn) {\n <a [routerLink]=\"column.linkFn(element)\" class=\"angular-a\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDateTime : getColumnFormat(column.type)) : ''}}\n </a>\n } @else {\n <p [class.angular-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDateTime : getColumnFormat(column.type)) : ''}}\n </p>\n }\n </td>\n } @else if(column.type == 'date-time-with-seconds'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n @if(column.linkFn) {\n <a [routerLink]=\"column.linkFn(element)\" class=\"angular-a\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDateTimeWithSeconds : getColumnFormat(column.type)) : ''}}\n </a>\n } @else {\n <p [class.angular-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | angularDateTimeWithSeconds : getColumnFormat(column.type)) : ''}}\n </p>\n }\n </td>\n } @else {\n <td mat-cell *matCellDef=\"let element\" class=\"3al-{{column.align}} 3ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n @if(column.linkFn) {\n <a [routerLink]=\"column.linkFn(element)\" class=\"angular-a\">\n @if (column.type == 'quantity') {\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | number : (getColumnFormat(column.type) || '1.4-4')) : '-' }}\n } @else if (column.type == 'money') {\n {{ column.valueKey && (getNestedValue(element, column.valueKey)) | angularCurrency : getColumnFormat(column.type) }}\n } @else {\n {{ column.valueKey && getNestedValue(element, column.valueKey) }}\n }\n </a>\n } @else {\n <p [class.angular-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n @if (column.type == 'quantity') {\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | number : (getColumnFormat(column.type) || '1.4-4')) : '-' }}\n } @else if (column.type == 'money') {\n {{ column.valueKey && (getNestedValue(element, column.valueKey)) | angularCurrency : getColumnFormat(column.type) }}\n } @else {\n {{ column.valueKey && getNestedValue(element, column.valueKey) }}\n }\n </p>\n }\n </td>\n }\n </ng-container>\n\n }\n\n\n @for(column of templateRenderColumns; track trackByTemplateColumn($index, column); let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"l\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px; cursor: pointer;\" (click)=\"expandAllRow()\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n <td mat-cell *matCellDef=\"let element\" class=\"4al-{{column.align}} 4ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <ng-container *ngIf=\"column.template as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colDef: column, colData: element }\"></ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n\n <!--Drag Column Def Start-->\n <ng-container [matColumnDef]=\"'drag'\" >\n <th mat-header-cell *matHeaderCellDef>\n --\n </th>\n <td mat-cell *matCellDef=\"let element\" class=\"5al-drag 5ty-drag\">\n <mat-icon cdkDragHandle class=\"angular-curser-pointer\" style=\"color: rgba(0, 0, 0, 0.54); font-size: 19px; width: 19px; height: 19px;\">drag_indicator</mat-icon>\n </td>\n </ng-container>\n <!--Drag Column Def End-->\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"displayedColumns.length\" [style.border-bottom-width]=\"isRowExpanded(element) ? '1px' : '0px'\" style=\"padding: 0px !important;\">\n <div class=\"angular-element-detail-wrapper\" [class.angular-element-detail-wrapper-expanded]=\"isRowExpanded(element)\">\n <ng-container *ngIf=\"expandedTemplate as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\" [attr.colspan]=\"displayedColumns.length\">\n <div class=\"angular-data-not-found\">\n @if(dataNotFoundConfig.iconUrl) {\n <img [src]=\"dataNotFoundConfig.iconUrl\" alt=\"No data found\" />\n } @else {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n }\n <h5 class=\"angular-h5\">{{dataNotFoundConfig.title}}</h5>\n </div>\n </td>\n </tr>\n\n <!-- Apply Drag and Drop to tbody -->\n @if(enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.angular-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\" cdkDrag></tr>\n }\n\n @if(!enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.angular-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\"></tr>\n } \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"angular-detail-row\"></tr>\n </table>\n <!--Table End-->\n }\n @else {\n <!-- Mobile Card View -->\n @if (dataSource?.apiSubject | async; as rows) {\n <table class=\"angular-table angular-mobile-responsive-table\" [class.angular-table-bordered]=\"disableBorderedView == false\">\n <tbody>\n @for (element of rows; track trackByTableRow($index, element)) {\n <tr [ngStyle]=\"{'background-color': getRowBackground(element) || 'inherit'}\" [class.angular-curser-pointer]=\"isExpandedRowForMobileResponsive\" (click)=\"(isExpansionForMobileResponsive && isExpandedRowForMobileResponsive) ? toggleExpandForMobileResponsive(element) : null\">\n <td>\n <div class=\"angular-table-responsive-table-wrapper\">\n <div class=\"angular-table-responsive-table-header-wrapper\">\n @if (enableRowsSelection) {\n <div class=\"angular-table-responsive-table-header-wrapper-item\">\n <mat-checkbox color=\"primary\" (click)=\"stopPropagation($event)\" (change)=\"$event ? toggleSelection($event, element) : null\" [checked]=\"isChecked(element) || hasSelectedAllRows\"></mat-checkbox>\n </div>\n }\n <div class=\"angular-table-responsive-table-header-wrapper-item\" style=\"flex: 1 1 0%;\">\n <ng-container *ngIf=\"headerTemplateForEachRowForMobileResponsive as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </div>\n <div class=\"angular-table-responsive-table-content-wrapper\" [class.angular-table-responsive-table-content-wrapper-expanded]=\"isRowExpandedForMobileResponsive(element)\">\n <ng-container *ngIf=\"expandedTemplateForMobileResponsive as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </div>\n </td>\n </tr>\n }\n </tbody>\n </table>\n }\n }\n\n </div>\n @if(loaderPosition == 'bottom'){\n @if(dataSource?.loading$ | async){\n <div class=\"angular-d-flex angular-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n @if (!hidePaginator) {\n <div class=\"angular-table-paginator\">\n <mat-paginator [length]=\"dataSource?.totalDataLength?.value\" [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\" showFirstLastButtons></mat-paginator>\n </div>\n }\n </div>\n </div>\n } @else {\n\n @if(dataNotFoundConfig) {\n <div class=\"angular-data-not-found\">\n @if(dataNotFoundConfig.iconUrl) {\n <img [src]=\"dataNotFoundConfig.iconUrl\" alt=\"No data found\" />\n } @else {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--angular-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n }\n <h5 class=\"angular-h5\">{{dataNotFoundConfig.title}}</h5>\n @if(dataNotFoundConfig.desc) {\n <p class=\"angular-p\">{{dataNotFoundConfig.desc}}</p>\n }\n @if((dataNotFoundConfig.btnUrl || dataNotFoundConfig?.btnClick) && dataNotFoundConfig.btnText) {\n <button mat-flat-button color=\"primary\" class=\"angular-text-upper\"\n (click)=\"handleButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.btnText}}\n </button>\n }\n @if((dataNotFoundConfig.secondBtnUrl || dataNotFoundConfig?.secondBtnClick) && dataNotFoundConfig.secondBtnText) {\n <button mat-stroked-button color=\"primary\" class=\"angular-text-upper\"\n (click)=\"handleSecondButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.secondBtnText}}\n </button>\n }\n </div>\n }\n\n }\n\n }\n\n </div>\n </div>\n</section>", styles: ["::ng-deep .sub-main-content{border:0px solid #f00;margin-top:56px;height:calc(100% - 56px);padding:15px;overflow:auto}.header-title{margin-top:8px;padding:7px 10px;color:#969a9c}.header-title h3{font-size:20px!important;font-weight:700}.header-menu{border:0px solid red;background:#fff;margin-top:1px;margin-bottom:0}.w-100{width:100%}.mat-mdc-table-sticky-border-elem-right{border-left:1px solid #e0e0e087}.mat-mdc-table-sticky-border-elem-left{border-right:1px solid #e0e0e087}.search-mat-form-field{width:100%}.filter-applied-section{overflow:auto}.angular-detail-row{height:0!important}.angular-element-detail-wrapper{overflow:hidden;max-height:0;transition:max-height 225ms ease}.angular-element-detail-wrapper-expanded{max-height:500px}.angular-table-bordered{border-collapse:collapse;width:100%}.angular-table-bordered th,.angular-table-bordered td{border-left:1px solid #e0e0e0}.angular-table-bordered th:first-child,.angular-table-bordered td:first-child{border-left:0px solid #e0e0e0}.angular-table-bordered .bg-unset{background-color:unset!important}.angular-table-responsive-table-wrapper{width:100%;display:flex;flex-direction:column}.angular-table-responsive-table-header-wrapper{width:100%;display:flex;flex-direction:row;gap:10px;align-items:center}.angular-table-responsive-table-content-wrapper{width:100%}@media (max-width: 575.98px){.search-mat-form-field{width:100%!important}}@media (min-width: 576px) and (max-width: 767.98px){.search-mat-form-field{width:100%!important}}\n"] }]
2841
+ }], ctorParameters: () => [{ type: i1$1.MatDialog }, { type: ApiService }, { type: i3$1.ActivatedRoute }, { type: i3$1.Router }, { type: i4.Location }, { type: i5.BreakpointObserver }, { type: i0.ChangeDetectorRef }], propDecorators: { columnCustomizationUrlConfig: [{
2842
+ type: Input,
2843
+ args: [{ required: true }]
2844
+ }], t: [{
2845
+ type: Input,
2846
+ args: [{ required: true }]
2847
+ }], componentName: [{
2848
+ type: Input,
2849
+ args: [{ required: true }]
2850
+ }], mainTitle: [{
2851
+ type: Input,
2852
+ args: [{ required: true }]
2853
+ }], searchPlaceholder: [{
2854
+ type: Input
2855
+ }], breadcrumbs: [{
2856
+ type: Input
2857
+ }], hideHeader: [{
2858
+ type: Input
2859
+ }], hideTableHeader: [{
2860
+ type: Input
2861
+ }], hidePaginator: [{
2862
+ type: Input
2863
+ }], keepFilterInUrl: [{
2864
+ type: Input
2865
+ }], disableBorderedView: [{
2866
+ type: Input
2867
+ }], displayColumnsSelectionButton: [{
2868
+ type: Input
2869
+ }], loadDataApiBaseUrl: [{
2870
+ type: Input
2871
+ }], startStickyColumnCount: [{
2872
+ type: Input
2873
+ }], endStickyColumnCount: [{
2874
+ type: Input
2875
+ }], isSearchFieldMobileResponsive: [{
2876
+ type: Input
2877
+ }], isMobileResponsiveTable: [{
2878
+ type: Input
2879
+ }], loaderPosition: [{
2880
+ type: Input
2881
+ }], dataNotFoundConfig: [{
2882
+ type: Input,
2883
+ args: [{ required: true }]
2884
+ }], showFilterButtonSection: [{
2885
+ type: Input
2886
+ }], columnValueTypeFormats: [{
2887
+ type: Input
2888
+ }], columnsCodeMapping: [{
2889
+ type: Input,
2890
+ args: [{ required: true }]
2891
+ }], defaultDisplayedColumns: [{
2892
+ type: Input
2893
+ }], displayedColumnsChange: [{
2894
+ type: Output
2895
+ }], defaultSortObj: [{
2896
+ type: Input
2897
+ }], sortObjChange: [{
2898
+ type: Output
2899
+ }], loadingSpinnerDiameter: [{
2900
+ type: Input
2901
+ }], pageSizeOptions: [{
2902
+ type: Input
2903
+ }], pageSize: [{
2904
+ type: Input
2905
+ }], pageSizeChange: [{
2906
+ type: Output
2907
+ }], useGlobalPageSize: [{
2908
+ type: Input
2909
+ }], pageIndex: [{
2910
+ type: Input
2911
+ }], pageIndexChange: [{
2912
+ type: Output
2913
+ }], filterFormGroup: [{
2914
+ type: Input
2915
+ }], rowsConfig: [{
2916
+ type: Input
2917
+ }], onDataLoaded: [{
2918
+ type: Output
2919
+ }], onSetExtraData: [{
2920
+ type: Output
2921
+ }], onSetTotal: [{
2922
+ type: Output
2923
+ }], hasSelectedAllRows: [{
2924
+ type: Input
2925
+ }], table: [{
2926
+ type: ViewChild,
2927
+ args: [MatTable]
2928
+ }], sort: [{
2929
+ type: ViewChild,
2930
+ args: [MatSort]
2931
+ }], paginator: [{
2932
+ type: ViewChild,
2933
+ args: [MatPaginator]
2934
+ }], enableRowsSelection: [{
2935
+ type: Input
2936
+ }], enableAllRowsSelection: [{
2937
+ type: Input
2938
+ }], onlySingleSelection: [{
2939
+ type: Input
2940
+ }], selectedRowIds: [{
2941
+ type: Input
2942
+ }], selectedRowKey: [{
2943
+ type: Input
2944
+ }], selectedRows: [{
2945
+ type: Input
2946
+ }], selectedRowsChange: [{
2947
+ type: Output
2948
+ }], allRowsSelectedChange: [{
2949
+ type: Output
2950
+ }], enableDragNDrop: [{
2951
+ type: Input
2952
+ }], listDataSequenceChange: [{
2953
+ type: Output
2954
+ }], isExpansion: [{
2955
+ type: Input
2956
+ }], isExpandedRow: [{
2957
+ type: Input
2958
+ }], expandedTemplate: [{
2959
+ type: Input
2960
+ }], isExpansionForMobileResponsive: [{
2961
+ type: Input
2962
+ }], isExpandedRowForMobileResponsive: [{
2963
+ type: Input
2964
+ }], expandedTemplateForMobileResponsive: [{
2965
+ type: Input
2966
+ }], headerTemplateForEachRowForMobileResponsive: [{
2967
+ type: Input
2968
+ }] } });
2969
+
2970
+ class Quantity {
2971
+ decimalPoints = 4;
2972
+ transform(value) {
2973
+ if (Number(value) > 0) {
2974
+ let roundValue = this.roundNumber(Number(value), this.decimalPoints);
2975
+ let roundValueArr = String(roundValue)?.split('.');
2976
+ if (roundValueArr?.length > 1) {
2977
+ let currentDesimal = roundValueArr[1];
2978
+ if (currentDesimal?.length < this.decimalPoints) {
2979
+ roundValue = `${roundValue}`;
2980
+ for (let index = 0; index < (this.decimalPoints - currentDesimal?.length); index++) {
2981
+ roundValue = `${roundValue}0`;
2982
+ }
2983
+ }
2984
+ }
2985
+ else {
2986
+ roundValue = `${roundValueArr[0]}.0000`;
2987
+ }
2988
+ return roundValue;
2989
+ }
2990
+ else {
2991
+ return 0;
2992
+ }
2993
+ }
2994
+ roundNumber(number, decimals = 0) {
2995
+ const multiplier = Math.pow(10, decimals);
2996
+ return Math.round(number * multiplier) / multiplier;
2997
+ }
2998
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: Quantity, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
2999
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.7", ngImport: i0, type: Quantity, isStandalone: false, name: "qty" });
3000
+ }
3001
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: Quantity, decorators: [{
3002
+ type: Pipe,
3003
+ args: [{
3004
+ name: 'qty',
3005
+ standalone: false
3006
+ }]
3007
+ }] });
3008
+
3009
+ class Money {
3010
+ decimalPoints = 4;
3011
+ transform(value) {
3012
+ if (Number(value) > 0) {
3013
+ let roundValue = this.roundNumber(Number(value), this.decimalPoints);
3014
+ let roundValueArr = String(roundValue)?.split('.');
3015
+ if (roundValueArr?.length > 1) {
3016
+ let currentDesimal = roundValueArr[1];
3017
+ if (currentDesimal?.length < this.decimalPoints) {
3018
+ roundValue = `${roundValue}`;
3019
+ for (let index = 0; index < (this.decimalPoints - currentDesimal?.length); index++) {
3020
+ roundValue = `${roundValue}0`;
3021
+ }
3022
+ }
3023
+ }
3024
+ else {
3025
+ roundValue = `${roundValueArr[0]}.0000`;
3026
+ }
3027
+ return roundValue;
3028
+ }
3029
+ else {
3030
+ return 0;
3031
+ }
3032
+ }
3033
+ roundNumber(number, decimals = 0) {
3034
+ const multiplier = Math.pow(10, decimals);
3035
+ return Math.round(number * multiplier) / multiplier;
3036
+ }
3037
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: Money, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
3038
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.7", ngImport: i0, type: Money, isStandalone: false, name: "money" });
3039
+ }
3040
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: Money, decorators: [{
3041
+ type: Pipe,
3042
+ args: [{
3043
+ name: 'money',
3044
+ standalone: false
3045
+ }]
3046
+ }] });
3047
+
3048
+ const directives = [
3049
+ ScrollingDirective
3050
+ ];
3051
+ const pipes = [
3052
+ AngularDatePipe,
3053
+ AngularDateTimePipe,
3054
+ AngularDateTimeWithSecondsPipe,
3055
+ AngularCurrencyPipe,
3056
+ Quantity,
3057
+ Money,
3058
+ ];
3059
+ const uiImports = [
3060
+ MatTooltipModule,
3061
+ MatIconModule,
3062
+ MatFormFieldModule,
3063
+ MatSelectModule,
3064
+ MatInputModule,
3065
+ MatSnackBarModule,
3066
+ MatProgressSpinnerModule,
3067
+ MatButtonModule,
3068
+ MatPaginatorModule,
3069
+ LayoutModule, // For Breakpoint Observer,
3070
+ MatDialogModule,
3071
+ MatTableModule,
3072
+ MatCheckboxModule,
3073
+ MatMenuModule,
3074
+ MatDividerModule,
3075
+ MatSortModule
3076
+ ];
3077
+ class AngularSmartDataTableModule {
3078
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
3079
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableModule, declarations: [ScrollingDirective, AngularDatePipe,
3080
+ AngularDateTimePipe,
3081
+ AngularDateTimeWithSecondsPipe,
3082
+ AngularCurrencyPipe,
3083
+ Quantity,
3084
+ Money, AngularSmartDataTableComponent,
3085
+ AngularColumnsBtnComponent,
3086
+ CreateColumnsTemplateComponent,
3087
+ AngularSmartDataTableErrorDialogComponent,
3088
+ AngularSmartDataTableConfirmationDialogComponent], imports: [CommonModule,
3089
+ FormsModule,
3090
+ ReactiveFormsModule,
3091
+ RouterLink,
3092
+ RouterOutlet, MatTooltipModule,
3093
+ MatIconModule,
3094
+ MatFormFieldModule,
3095
+ MatSelectModule,
3096
+ MatInputModule,
3097
+ MatSnackBarModule,
3098
+ MatProgressSpinnerModule,
3099
+ MatButtonModule,
3100
+ MatPaginatorModule,
3101
+ LayoutModule, // For Breakpoint Observer,
3102
+ MatDialogModule,
3103
+ MatTableModule,
3104
+ MatCheckboxModule,
3105
+ MatMenuModule,
3106
+ MatDividerModule,
3107
+ MatSortModule, DragDropModule], exports: [AngularSmartDataTableComponent] });
3108
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableModule, imports: [CommonModule,
3109
+ FormsModule,
3110
+ ReactiveFormsModule, uiImports, DragDropModule] });
3111
+ }
3112
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: AngularSmartDataTableModule, decorators: [{
3113
+ type: NgModule,
3114
+ args: [{
3115
+ declarations: [
3116
+ ...directives,
3117
+ ...pipes,
3118
+ AngularSmartDataTableComponent,
3119
+ AngularColumnsBtnComponent,
3120
+ CreateColumnsTemplateComponent,
3121
+ AngularSmartDataTableErrorDialogComponent,
3122
+ AngularSmartDataTableConfirmationDialogComponent
3123
+ ],
3124
+ imports: [
3125
+ CommonModule,
3126
+ FormsModule,
3127
+ ReactiveFormsModule,
3128
+ RouterLink,
3129
+ RouterOutlet,
3130
+ ...uiImports,
3131
+ DragDropModule
3132
+ ],
3133
+ exports: [
3134
+ AngularSmartDataTableComponent
3135
+ ]
3136
+ }]
3137
+ }] });
3138
+
3139
+ /*
3140
+ * Public API Surface of angular-smart-data-table
3141
+ */
3142
+
3143
+ /**
3144
+ * Generated bundle index. Do not edit.
3145
+ */
3146
+
3147
+ export { AngularSmartDataTableComponent, AngularSmartDataTableModule, AngularSmartDataTableService };
3148
+ //# sourceMappingURL=servicemind.tis-angular-smart-data-table.mjs.map