@angular-generic-table/core 5.0.0-rc.16 → 5.0.0-rc.18

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.
@@ -1,8 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, Pipe, Injector, EventEmitter, Component, ChangeDetectionStrategy, Input, Output, NgModule } from '@angular/core';
3
- import { ReplaySubject, BehaviorSubject, isObservable, of, combineLatest } from 'rxjs';
3
+ import { Subject, ReplaySubject, BehaviorSubject, isObservable, of, combineLatest, fromEvent } from 'rxjs';
4
+ import * as i1 from '@angular/common';
4
5
  import { KeyValuePipe, AsyncPipe, NgTemplateOutlet, SlicePipe, NgClass, NgIf, NgForOf, PercentPipe, CommonModule } from '@angular/common';
5
- import { debounceTime, distinctUntilChanged, tap, shareReplay, startWith, map, switchMap, withLatestFrom, take, pluck } from 'rxjs/operators';
6
+ import { distinctUntilChanged, tap, shareReplay, startWith, map, switchMap, withLatestFrom, filter, pluck, take, takeUntil } from 'rxjs/operators';
6
7
 
7
8
  class CoreService {
8
9
  constructor() { }
@@ -144,6 +145,7 @@ let calculate = (data, config) => {
144
145
  };
145
146
  };
146
147
  /** sortOnMultipleKeys
148
+ * @description Sort data on multiple keys
147
149
  * @param {GtSortOrder} keys - array with sort config objects to sort on, data will be sorted according to array order
148
150
  * @returns sort function
149
151
  */
@@ -160,6 +162,40 @@ const sortOnMultipleKeys = (keys) => {
160
162
  return 0;
161
163
  };
162
164
  };
165
+ /** parseSortOrderParams
166
+ * @description Convert sort order query param to array with sort config objects
167
+ * @param sortParams - Query param string where each sort config object is separated by comma and order is indicated by + (ascending) or - (descending), e.g. _'name,-age'_
168
+ * @returns GtSortOrder - Array with sort config objects
169
+ */
170
+ const parseSortOrderParams = (sortParams) => {
171
+ const sortParamsArray = sortParams.split(',');
172
+ return sortParamsArray.map((sortParam) => {
173
+ const [key, order] = sortParam.split(':');
174
+ return {
175
+ key: key.replace(/^[+-]/, ''),
176
+ order: order === 'desc' ? 'desc' : 'asc',
177
+ };
178
+ });
179
+ };
180
+ /** sortOrderConfigToParam
181
+ * @description Convert sort config object to string that can be used as query param when sorting is implemented server side
182
+ * @param sortConfig - Sort config object
183
+ * @returns string - Query param string where order is indicated by + (ascending) or - (descending), e.g. _'-name'_
184
+ */
185
+ const sortOrderConfigToParam = (sortConfig) => {
186
+ const order = sortConfig.order === 'desc' ? '-' : '+';
187
+ return `${order}${sortConfig.key}`;
188
+ };
189
+ /** sortOrderToParams
190
+ * @description Convert sort order array to string that can be used as query param when sorting is implemented server side
191
+ * @param sortOrder - Array with sort config objects
192
+ * @returns string - Query param string where each sort config object is separated by comma and order is indicated by + (ascending) or - (descending), e.g. _'name,-age'_
193
+ */
194
+ const sortOrderToParams = (sortOrder) => {
195
+ return sortOrder
196
+ .map((sortConfig) => sortOrderConfigToParam(sortConfig))
197
+ .join(',');
198
+ };
163
199
 
164
200
  class CapitalCasePipe {
165
201
  transform(s) {
@@ -300,21 +336,84 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImpor
300
336
  }]
301
337
  }] });
302
338
 
339
+ class RowSelectionPipe {
340
+ transform(row, selection, comparator, className) {
341
+ return className && comparator(row, selection) ? className : '';
342
+ }
343
+ }
344
+ RowSelectionPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: RowSelectionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
345
+ RowSelectionPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: RowSelectionPipe, isStandalone: true, name: "rowSelection" });
346
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: RowSelectionPipe, decorators: [{
347
+ type: Pipe,
348
+ args: [{
349
+ name: 'rowSelection',
350
+ standalone: true,
351
+ }]
352
+ }] });
353
+
303
354
  class CoreComponent {
304
355
  constructor() {
356
+ this.unsubscribe$ = new Subject();
357
+ this._navigationKeys = [
358
+ 'ArrowDown',
359
+ 'ArrowUp',
360
+ 'ArrowLeft',
361
+ 'ArrowRight',
362
+ 'Home',
363
+ 'End',
364
+ ];
365
+ this._selectKeys = ['Enter', ' '];
366
+ this._customClasses = {
367
+ selectedRow: 'gt-selected',
368
+ activeRow: 'gt-active',
369
+ };
370
+ /** selection
371
+ * @description An object that contains the currently selected row(s) in the table. It's passed to the selection function to determine which rows should be selected.
372
+ * @type {any}
373
+ */
374
+ this.selection = {};
375
+ /** generateRowId
376
+ * @description Whether or not to generate a unique id for each row in the table. Defaults to `true`.
377
+ * @type {boolean}
378
+ */
379
+ this.generateRowId = true;
305
380
  this.rowClick = new EventEmitter();
381
+ this.rowSelect = new EventEmitter();
306
382
  this.sortOrderChange = new EventEmitter();
307
- this._rowHover$ = new ReplaySubject(1);
308
- this.rowHover = new EventEmitter();
383
+ this._rowActive$ = new ReplaySubject(1);
384
+ this.rowActive = new EventEmitter();
309
385
  this.columnSort = new EventEmitter();
310
- this.rowHover$ = this._rowHover$.asObservable().pipe(debounceTime(50), distinctUntilChanged((p, q) => p.index === q.index), tap((event) => this.rowHover.emit(event)), shareReplay(1));
386
+ /** page change event - emitted when current page/index changes for pagination */
387
+ this.pageChange = new EventEmitter();
388
+ this.rowActive$ = this._rowActive$.asObservable().pipe(distinctUntilChanged((p, q) => {
389
+ if (this.rowIdKey && p.row && q.row) {
390
+ return p.row[this.rowIdKey] === q.row[this.rowIdKey];
391
+ }
392
+ else if (this.generateRowId && p.row && q.row) {
393
+ return p.row._id === q.row._id;
394
+ }
395
+ else {
396
+ return p.index === q.index;
397
+ }
398
+ }), tap((event) => (this.activeRowIndex = event.index)), tap((event) => this.rowActive.emit(event)), shareReplay(1));
399
+ this.activeRowIndex = null;
311
400
  this._loading$ = new ReplaySubject(1);
312
401
  this._sortOrder$ = new BehaviorSubject([]);
313
402
  this._searchBy$ = new ReplaySubject(1);
314
403
  this.searchBy$ = this._searchBy$.pipe(startWith(''), map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => obs), shareReplay(1));
404
+ this._pagingInfo$ = new BehaviorSubject({
405
+ pageCurrent: null,
406
+ pageNext: null,
407
+ pagePrevious: null,
408
+ pageSize: null,
409
+ numberOfRecords: null,
410
+ //recordsAfterFilter: null,
411
+ //recordsAfterSearch: null,
412
+ //recordsAll: null,
413
+ });
315
414
  // tslint:disable-next-line:variable-name
316
415
  this._tableConfig$ = new BehaviorSubject({});
317
- this.tableConfig$ = this._tableConfig$.pipe(map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => obs), shareReplay(1));
416
+ this.tableConfig$ = this._tableConfig$.pipe(map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => obs), tap((config) => (this._tableConfig = config)), shareReplay(1));
318
417
  this._data$ = new ReplaySubject(1);
319
418
  this.data$ = this._data$.pipe(map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => combineLatest([obs])), withLatestFrom(this.tableConfig$), map(([[data], config]) => {
320
419
  // if columns or rows contains config for mapTo...
@@ -336,15 +435,22 @@ class CoreComponent {
336
435
  }
337
436
  data = newData;
338
437
  }
438
+ if (this.generateRowId && !this.rowIdKey && data.length > 0) {
439
+ const dataWithId = [];
440
+ for (let i = 0; i < data.length; i++) {
441
+ dataWithId[i] = { ...data[i], _id: i };
442
+ }
443
+ data = dataWithId;
444
+ }
339
445
  return { data, config };
340
446
  }), switchMap((obs) => combineLatest([of(obs), this.sortOrder$, this.searchBy$])), map(([table, sortBy, searchBy]) => {
341
447
  // create a new array reference and sort new array (prevent mutating existing state)
342
448
  table.data = [...table.data];
343
- return !sortBy.length || table.config?.disableTableSort
344
- ? searchBy
449
+ return !sortBy?.length || table.config?.disableTableSort
450
+ ? searchBy && !this.tableInfo?.lazyLoaded
345
451
  ? search(searchBy, false, table.data, table.config)
346
452
  : table.data
347
- : searchBy
453
+ : searchBy && !this.tableInfo?.lazyLoaded
348
454
  ? search(searchBy, false, table.data, table.config)?.sort(sortOnMultipleKeys(sortBy))
349
455
  : table.data?.sort(sortOnMultipleKeys(sortBy));
350
456
  }), shareReplay(1));
@@ -352,14 +458,30 @@ class CoreComponent {
352
458
  this.table$ = combineLatest([
353
459
  this.data$,
354
460
  this.tableConfig$,
355
- ]).pipe(map(([sorted, config]) => {
461
+ this._pagingInfo$,
462
+ ]).pipe(map(([sorted, config, pagingInfo]) => {
463
+ if (pagingInfo.pageCurrent !== null &&
464
+ pagingInfo.numberOfRecords !== null &&
465
+ pagingInfo.pageSize !== null) {
466
+ return {
467
+ data: [sorted],
468
+ config,
469
+ info: {
470
+ lazyLoaded: true,
471
+ numberOfRecords: pagingInfo.numberOfRecords,
472
+ pageSize: pagingInfo.pageSize,
473
+ pageTotal: pagingInfo.pageTotal ??
474
+ Math.ceil(pagingInfo.numberOfRecords / pagingInfo.pageSize),
475
+ },
476
+ };
477
+ }
356
478
  // if pagination is disabled...
357
479
  if (!config.pagination || config.pagination.length === 0) {
358
480
  // ...return unaltered array
359
481
  return {
360
482
  data: [sorted],
361
483
  config,
362
- info: { records: sorted.length, pageTotal: 1 },
484
+ info: { numberOfRecords: sorted.length, pageTotal: 1 },
363
485
  };
364
486
  }
365
487
  // return record set
@@ -367,19 +489,25 @@ class CoreComponent {
367
489
  data: chunk(sorted, +(config.pagination.length || 0)),
368
490
  config,
369
491
  info: {
370
- records: sorted.length,
492
+ numberOfRecords: sorted.length,
493
+ pageSize: +(config.pagination.length || 0),
371
494
  pageTotal: Math.ceil(sorted.length / +(config.pagination.length || 0)),
372
495
  },
373
496
  };
374
- }), shareReplay(1));
375
- this._currentPage$ = new BehaviorSubject(0);
376
- this.currentPage$ = combineLatest([this._currentPage$, this.table$]).pipe(map(([page, table]) => {
497
+ }), tap((meta) => this._tableInfo$.next(meta.info)), shareReplay(1));
498
+ this._tableInfo$ = new BehaviorSubject(undefined);
499
+ this._currentPaginationIndex$ = new BehaviorSubject(0);
500
+ this.currentPaginationIndex$ = combineLatest([
501
+ this._currentPaginationIndex$,
502
+ this.table$,
503
+ ]).pipe(map(([page, table]) => {
377
504
  // determine last page
378
505
  const lastPage = Math.ceil(table.info.records /
379
- (table.config?.pagination?.length || table.info.records)) - 1;
380
- // determine max/min position
506
+ (table.info.recordLength ??
507
+ (table.config?.pagination?.length || table.info.records))) - 1;
508
+ // determine min/max position
381
509
  return +page < 0 ? 0 : +page > lastPage ? lastPage : +page;
382
- }), shareReplay(1));
510
+ }), distinctUntilChanged(), tap((index) => this.pageChange.emit({ index })), shareReplay(1));
383
511
  this.colspan$ = this.tableConfig$.pipe(switchMap((config) => config.columns
384
512
  ? of(Object.values(config.columns || config.rows || {}).filter((value) => value.hidden !== true).length)
385
513
  : this.data$.pipe(map((data) => data.length + 1))), shareReplay(1));
@@ -396,6 +524,30 @@ class CoreComponent {
396
524
  this.columnOrder = (a, b) => {
397
525
  return (a.value.order || 0) - (b.value.order || 0);
398
526
  };
527
+ this._unsubscribeFromKeyboardEvents$ = new Subject();
528
+ this._keyboardArrowEvent$ = fromEvent(document, 'keydown').pipe(filter((event) => [...this._navigationKeys, ...this._selectKeys].indexOf(event.key) > -1));
529
+ }
530
+ get navigationKeys() {
531
+ return this._navigationKeys;
532
+ }
533
+ /** navigationKeys
534
+ * @description An array of keyboard keys that will trigger navigation and active row, currently only supports arrow keys, home and end (omit key name from array to disable it)
535
+ * @type {string[]}
536
+ * @default ['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Home', 'End']
537
+ */
538
+ set navigationKeys(value) {
539
+ this._navigationKeys = value;
540
+ }
541
+ get selectKeys() {
542
+ return this._selectKeys;
543
+ }
544
+ /** selectKeys
545
+ * @description An array of keyboard keys that will trigger row selection (omit key name from array to disable it)
546
+ * @type {string[]}
547
+ * @default ['Enter', ' ']
548
+ */
549
+ set selectKeys(value) {
550
+ this._selectKeys = value;
399
551
  }
400
552
  get sortOrder$() {
401
553
  return this._sortOrder$.asObservable();
@@ -403,8 +555,52 @@ class CoreComponent {
403
555
  set loading(isLoading) {
404
556
  this._loading$.next(isLoading);
405
557
  }
406
- set page(page) {
407
- this._currentPage$.next(page);
558
+ set paginationIndex(pageIndex) {
559
+ this._currentPaginationIndex$.next(pageIndex);
560
+ }
561
+ get paginationIndex() {
562
+ return this._currentPaginationIndex$.getValue();
563
+ }
564
+ set pagingInfo(value) {
565
+ if (value) {
566
+ this._pagingInfo$.next(value);
567
+ if (value.pageCurrent !== this._currentPaginationIndex$.getValue() + 1 &&
568
+ value.pageCurrent !== null) {
569
+ this.paginationIndex = value.pageCurrent - 1;
570
+ }
571
+ }
572
+ }
573
+ /** customClasses
574
+ * @description An object that contains custom classes for various elements in the table.
575
+ * @type {object} - { selectedRow: string, activeRow: string } - default classes are 'gt-selected' and 'gt-active'
576
+ */
577
+ set customClasses(classes) {
578
+ this._customClasses = { ...this._customClasses, ...classes };
579
+ }
580
+ get customClasses() {
581
+ return this._customClasses;
582
+ }
583
+ /** isRowSelectedFn
584
+ * @description Function to determine if row is selected or not.
585
+ * @type {fn} A function that receives a row object and optional state for current selection that can be used to determine if row should be marked as selected or not. */
586
+ set isRowSelectedFn(fn) {
587
+ this._isRowSelectedFn = fn;
588
+ }
589
+ get isRowSelectedFn() {
590
+ return this._isRowSelectedFn;
591
+ }
592
+ /** trackRowByFn
593
+ * @description A function that returns a unique identifier for each row in the table to optimize rendering when data is added or removed.
594
+ * @type fn - TrackByFunction to retrieve unique id based on index and/or row. Defaults to using `row[this.rowIdKey]`.
595
+ */
596
+ set trackRowByFn(fn) {
597
+ this._trackRowByFn = fn;
598
+ }
599
+ get trackRowByFn() {
600
+ return this._trackRowByFn;
601
+ }
602
+ _trackRowByFn(index, row) {
603
+ return this.rowIdKey ? row[this.rowIdKey] : row?._id;
408
604
  }
409
605
  set search(string) {
410
606
  this._searchBy$.next(string);
@@ -413,7 +609,9 @@ class CoreComponent {
413
609
  this._tableConfig$.next(config);
414
610
  }
415
611
  set data(data) {
416
- this._data$.next(data);
612
+ if (data) {
613
+ this._data$.next(data);
614
+ }
417
615
  }
418
616
  set sortOrder(sortConfig) {
419
617
  if (JSON.stringify(sortConfig) !== JSON.stringify(this._sortOrder$.value)) {
@@ -424,31 +622,44 @@ class CoreComponent {
424
622
  _rowClick(row, index, event) {
425
623
  this.rowClick.emit({ row, index, event });
426
624
  }
427
- hoverRow(arg) {
625
+ _rowActive(row, index, event) {
626
+ this.rowSelect.emit({ row, index, event });
627
+ }
628
+ activateRow(arg, event) {
428
629
  if (typeof arg === 'number') {
429
- this.data$
430
- .pipe(map((data) => data[arg]), take(1))
431
- .subscribe((row) => this._hoverRow(row, arg));
630
+ this.table$
631
+ .pipe(pluck('data'), map((data) => data[this.paginationIndex][arg]), take(1), takeUntil(this.unsubscribe$))
632
+ .subscribe((row) => this._activateRow(row, arg, event));
432
633
  }
433
634
  else if (typeof arg === 'string') {
434
635
  // TODO: implement hover by id
435
636
  }
436
637
  else {
437
- this._hoverRow(null, null);
638
+ this._activateRow(null, null);
438
639
  }
439
640
  }
440
- _hoverRow(row, index, event) {
441
- this._rowHover$.next({ row, index, event });
641
+ _activateRow(row, index, event) {
642
+ this._rowActive$.next({ row, index, event });
442
643
  }
443
644
  get loading$() {
444
645
  return this._loading$.pipe(startWith(false), map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => obs), shareReplay(1));
445
646
  }
647
+ /** tableInfo$ - returns observable for table info
648
+ * @return Observable<TableInfo> */
649
+ get tableInfo$() {
650
+ return this._tableInfo$.asObservable().pipe(filter((info) => !!info), shareReplay(1));
651
+ }
652
+ /** tableInfo - returns the current table info
653
+ * @return TableInfo */
654
+ get tableInfo() {
655
+ return this._tableInfo$.getValue();
656
+ }
446
657
  /** sortByKey - Sort by key in table row
447
658
  * @param key - key to sort by
448
659
  * @param { MouseEvent } [$event] - Mouse event triggering sort, if shift key is pressed sort key will be added to already present sort keys
449
660
  */
450
661
  sortByKey(key, $event) {
451
- const shiftKey = $event?.shiftKey;
662
+ const shiftKey = $event?.shiftKey === true;
452
663
  const currentOrder = this._sortOrder$.value;
453
664
  let sortOrder = 'asc';
454
665
  let newOrder = [];
@@ -496,6 +707,7 @@ class CoreComponent {
496
707
  key,
497
708
  order: sortOrder,
498
709
  currentSortOrder: newOrder,
710
+ addSortKey: shiftKey,
499
711
  };
500
712
  // if event is passed to sort function...
501
713
  if ($event) {
@@ -504,17 +716,128 @@ class CoreComponent {
504
716
  }
505
717
  // emit sort event
506
718
  this.columnSort.emit(sortEvent);
507
- // update sort order
508
- this.sortOrder = newOrder;
719
+ // if table is not lazy loaded (sorting is then handled server-side)...
720
+ if (!this.tableInfo?.lazyLoaded) {
721
+ // ...update sort order
722
+ this.sortOrder = newOrder;
723
+ }
509
724
  }
510
725
  nestedValue(object, mapTo, missingValue = null) {
511
726
  const levels = mapTo.split('.');
512
727
  return levels.reduce((previousValue, currentValue, index) => previousValue[currentValue] ||
513
728
  (index === levels.length - 1 ? missingValue : {}), object);
514
729
  }
730
+ listenToKeyboardEvents() {
731
+ if (!this._tableConfig?.activateRowOnKeyboardNavigation) {
732
+ return;
733
+ }
734
+ this._unsubscribeFromKeyboardEvents$.next(true);
735
+ this._keyboardArrowEvent$
736
+ .pipe(withLatestFrom(this.data$, this.currentPaginationIndex$, this.tableInfo$), takeUntil(this._unsubscribeFromKeyboardEvents$), takeUntil(this.unsubscribe$))
737
+ .subscribe(([event, rows, currentPage, tableInfo]) => {
738
+ const selectEvent = this._selectKeys.includes(event.key);
739
+ if (selectEvent && this.activeRowIndex !== null) {
740
+ const rowIndex = this.activeRowIndex + currentPage * (tableInfo?.pageSize ?? 0);
741
+ this._rowActive(rows[rowIndex], rowIndex, event);
742
+ return;
743
+ }
744
+ const navigationEvent = this._navigationKeys.includes(event.key);
745
+ if (navigationEvent) {
746
+ this._handleNavigationEvent(event, rows, currentPage, tableInfo);
747
+ }
748
+ });
749
+ }
750
+ unsubscribeFromKeyboardEvents(tableRef) {
751
+ if (!this._tableConfig?.activateRowOnKeyboardNavigation) {
752
+ return;
753
+ }
754
+ // only unsubscribe if table is not focused
755
+ if (tableRef !== document.activeElement) {
756
+ if (this._tableConfig?.activateRowOnHover) {
757
+ // unset active row
758
+ this.activateRow(null);
759
+ }
760
+ this._unsubscribeFromKeyboardEvents$.next(true);
761
+ }
762
+ }
763
+ _handleNavigationEvent(event, rows, currentPage, tableInfo) {
764
+ const hasPagination = (tableInfo?.pageTotal || 0) > 1 && tableInfo;
765
+ const lastRowIndex = rows.length - 1;
766
+ let newIndex = this.activeRowIndex;
767
+ let indexModifier = 0;
768
+ if (event.key === 'Home') {
769
+ this.paginationIndex = 0;
770
+ this.activateRow(0, event);
771
+ return;
772
+ }
773
+ if (event.key === 'End') {
774
+ const indexOfLastRecord = hasPagination
775
+ ? rows.length - (tableInfo.pageTotal - 1) * tableInfo.pageSize - 1
776
+ : lastRowIndex;
777
+ if (tableInfo?.pageTotal) {
778
+ this.paginationIndex = tableInfo.pageTotal - 1;
779
+ }
780
+ this.activateRow(indexOfLastRecord, event);
781
+ return;
782
+ }
783
+ if (event.key === 'ArrowDown') {
784
+ indexModifier = 1;
785
+ }
786
+ else if (event.key === 'ArrowUp') {
787
+ indexModifier = -1;
788
+ }
789
+ if (newIndex === null) {
790
+ newIndex = 0;
791
+ }
792
+ else if (newIndex + indexModifier >= 0 &&
793
+ newIndex + indexModifier <= lastRowIndex) {
794
+ newIndex = newIndex + indexModifier;
795
+ }
796
+ if (hasPagination && tableInfo?.pageSize) {
797
+ const isNotLastPage = currentPage + 1 < tableInfo.pageTotal;
798
+ const recordsOnLastPage = rows.length - (tableInfo.pageTotal - 1) * tableInfo.pageSize - 1;
799
+ const maxIndex = isNotLastPage
800
+ ? tableInfo?.pageSize - 1
801
+ : recordsOnLastPage;
802
+ if (event.key === 'ArrowLeft' && currentPage > 0) {
803
+ this.paginationIndex = currentPage - 1;
804
+ this.activateRow(newIndex, event);
805
+ return;
806
+ }
807
+ else if (event.key === 'ArrowRight' && isNotLastPage) {
808
+ if (currentPage + 1 === tableInfo.pageTotal - 1 &&
809
+ newIndex > recordsOnLastPage) {
810
+ this.activateRow(recordsOnLastPage, event);
811
+ }
812
+ this.paginationIndex = currentPage + 1;
813
+ this.activateRow(newIndex, event);
814
+ return;
815
+ }
816
+ if (currentPage > 0 &&
817
+ indexModifier < 0 &&
818
+ newIndex + indexModifier <= lastRowIndex &&
819
+ (this.activeRowIndex || 0) + indexModifier < 0) {
820
+ // set last row of previous page as active
821
+ this.activateRow(tableInfo?.pageSize - 1, event);
822
+ this.paginationIndex = currentPage - 1;
823
+ return;
824
+ }
825
+ const pageIndex = newIndex % tableInfo?.pageSize;
826
+ if (newIndex > maxIndex && currentPage + 1 < tableInfo.pageTotal) {
827
+ this.paginationIndex = currentPage + 1;
828
+ }
829
+ this.activateRow(pageIndex > maxIndex ? maxIndex : pageIndex, event);
830
+ return;
831
+ }
832
+ this.activateRow(newIndex, event);
833
+ }
834
+ ngOnDestroy() {
835
+ this.unsubscribe$.next(true);
836
+ this.unsubscribe$.complete();
837
+ }
515
838
  }
516
839
  CoreComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CoreComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
517
- CoreComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.1", type: CoreComponent, isStandalone: true, selector: "angular-generic-table", inputs: { loading: "loading", page: "page", search: "search", config: "config", data: "data", sortOrder: "sortOrder" }, outputs: { rowClick: "rowClick", sortOrderChange: "sortOrderChange", rowHover: "rowHover", columnSort: "columnSort" }, ngImport: i0, template: "<table\n [ngClass]=\"(tableConfig$ | async)?.class || 'table'\"\n [class.table-mobile]=\"(tableConfig$ | async)?.mobileLayout\"\n [class.table-horizontal]=\"(tableConfig$ | async)?.rows\"\n [class.table-loading]=\"loading$ | async\"\n [class.gt-sticky-row-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.row && (tableConfig$ | async)?.rows\n \"\n [class.gt-sticky-column-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.column\n \"\n [attr.aria-busy]=\"(loading$ | async) === true ? true : null\"\n>\n <thead>\n <tr\n *ngIf=\"{\n config: (tableConfig$ | async)!,\n isLoading: loading$ | async\n } as table\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <th\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [class.disabled]=\"table.isLoading\"\n [attr.aria-sort]=\"sortOrder$ | async | sortClass: column.key:'aria'\"\n [class.gt-sortable]=\"true\"\n scope=\"col\"\n >\n <button\n *ngIf=\"column.value?.sortable\"\n [attr.data-sort-order]=\"\n sortOrder$ | async | sortClass: column.key:'order'\n \"\n class=\"gt-sort\"\n (click)=\"\n table.isLoading ||\n !column.value.sortable ||\n sortByKey(column.key, $event)\n \"\n >\n <span *ngIf=\"column.value?.header !== false\">{{\n column.value.header || column.key | capitalCase\n }}</span>\n </button>\n <span\n *ngIf=\"!column.value?.sortable && column.value?.header !== false\"\n >{{ column.value.header || column.key | capitalCase }}</span\n >\n </th>\n </ng-container>\n <ng-container\n *ngIf=\"\n ((table?.config?.rows | keyvalue: columnOrder) || [])[0] as headerRow\n \"\n >\n <th\n class=\"row-header\"\n [attr.aria-sort]=\"\n sortOrder$ | async | sortClass: headerRow.key:'aria'\n \"\n ngClass=\"{{ headerRow.value.sortable ? 'sort ' : '' }} {{\n sortOrder$ | async | sortClass: headerRow.key\n }} {{ (headerRow.key | dashCase) + '-column' }}\"\n (click)=\"\n table.isLoading ||\n !headerRow.value.sortable ||\n sortByKey(headerRow.key, $event)\n \"\n scope=\"col\"\n >\n <ng-container *ngIf=\"headerRow?.value?.header !== false\">{{\n headerRow?.value?.header || headerRow.key | capitalCase\n }}</ng-container>\n </th>\n <th\n *ngFor=\"let column of ((table$ | async)?.data || [])[0]\"\n ngClass=\"{{ headerRow.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[headerRow.key].templateRef\n ? templateRef\n : (table.config.rows || {})[headerRow.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: headerRow,\n transform: (table.config.rows || {})[headerRow.key].transform,\n templateRef: (table.config.rows || {})[headerRow.key].templateRef,\n index: 0\n }\"\n >\n </ng-container>\n </th>\n </ng-container>\n </tr>\n </thead>\n <tbody *ngIf=\"loading$ | async; else tableContent\">\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-loading\"></ng-content>\n </td>\n </tr>\n </tbody>\n <tfoot *ngIf=\"(table$ | async)! as table\">\n <ng-container *ngIf=\"table.data.length > 0 && !(loading$ | async)\">\n <ng-container *ngIf=\"(calculations$ | async)! as calculations\">\n <tr\n *ngFor=\"let calculation of calculations.calculations; let i = index\"\n >\n <ng-container\n *ngIf=\"{\n showHeader: (colspan$ | async) !== (footerColspan$ | async)\n } as footerRow\"\n >\n <th\n *ngIf=\"footerRow.showHeader\"\n [colSpan]=\"\n ((colspan$ | async) || 0) - ((footerColspan$ | async) || 0)\n \"\n scope=\"row\"\n >\n <ng-container\n *ngIf=\"table.config?.footer?.headers?.[calculation] as showHeader\"\n >{{showHeader === true ? (calculation | capitalCase): table.config.footer?.headers?.[calculation]}}\n </ng-container>\n </th>\n <ng-container\n *ngFor=\"\n let column of table.config?.columns | keyvalue: columnOrder\n \"\n >\n <td\n *ngIf=\"\n !column.value?.hidden && calculations.calculated[column.key]\n \"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-header]=\"\n !footerRow.showHeader && table.config.footer?.headers?.[calculation]\n ? table.config.footer?.headers?.[calculation] === true ? (calculation | capitalCase) : table.config.footer?.headers?.[calculation]\n : null\n \"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n [class.gt-no-content]=\"\n !calculations.calculated[column.key][calculation]\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformFooter\n : rawFooter\n \"\n [ngTemplateOutletContext]=\"{\n value: calculations.calculated[column.key][calculation],\n row: calculations.calculated[column.key],\n column: calculation,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n transform: (table.config.columns || {})[column.key]\n .transform\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </ng-container>\n </tr>\n </ng-container>\n </ng-container>\n </tfoot>\n</table>\n<ng-template #tableContent>\n <ng-container *ngIf=\"(table$ | async)! as table\">\n <tbody *ngIf=\"(table!.data![0] || table!.data!).length > 0; else noData\">\n <ng-container *ngIf=\"table.config.columns\">\n <tr\n *ngFor=\"\n let row of table!.data![(currentPage$ | async) || 0];\n let i = index\n \"\n [attr.id]=\"'tableRow_' + i\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseover)=\"table?.config?.rowHover && _hoverRow(row, i, $event)\"\n (mouseout)=\"table?.config?.rowHover && _hoverRow(null, null, $event)\"\n [class.gt-hover]=\"(rowHover$ | async)?.index === i\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <td\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (searchBy$ | async) &&\n !(table.config.columns || {})[column.key].templateRef\n ? highlighted\n : (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: row,\n column: column,\n search: (searchBy$ | async),\n transform: (table.config.columns || {})[column.key].transform,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n index: i,\n data: table.data[(currentPage$ | async) || 0]\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </tr>\n </ng-container>\n <ng-container *ngIf=\"table.config.rows\">\n <ng-container\n *ngFor=\"\n let row of table?.config?.rows | keyvalue: columnOrder | slice: 1;\n let i = index\n \"\n >\n <tr\n *ngIf=\"!row.value?.hidden\"\n [attr.id]=\"'tableRow_' + i\"\n ngClass=\"{{ (row.key | dashCase) + '-row' }}\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseover)=\"table?.config?.rowHover && _hoverRow(row, i, $event)\"\n (mouseout)=\"\n table?.config?.rowHover && _hoverRow(null, null, $event)\n \"\n [class.gt-hover]=\"(rowHover$ | async)?.index === i\"\n >\n <th class=\"row-header\" scope=\"row\">\n {{ row.value.header || row.key | capitalCase }}\n </th>\n <td\n *ngFor=\"let column of (table?.data || [])[0]; let y = index\"\n ngClass=\"{{ row.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[row.key].templateRef\n ? templateRef\n : (table.config.rows || {})[row.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: row,\n transform: (table.config.rows || {})[row.key].transform,\n templateRef: (table.config.rows || {})[row.key].templateRef,\n index: table.config.rows ? y : i,\n data: table.data[(currentPage$ | async) || 0]\n }\"\n >\n </ng-container>\n </td>\n </tr>\n </ng-container>\n </ng-container>\n </tbody>\n </ng-container>\n</ng-template>\n<ng-template #noData>\n <tbody>\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-no-data\"></ng-content>\n </td>\n </tr>\n </tbody>\n</ng-template>\n<ng-template\n #highlighted\n let-row=\"row\"\n let-column=\"column\"\n let-search=\"search\"\n let-transform=\"transform\"\n>\n <div\n *ngIf=\"!transform\"\n [innerHTML]=\"row[column.key] | highlight: search\"\n ></div>\n <div\n *ngIf=\"transform\"\n [innerHTML]=\"\n row[column.key]\n | dynamicPipe: transform.pipe:transform?.args\n | highlight: search\n \"\n ></div>\n</ng-template>\n<ng-template #rawData let-row=\"row\" let-column=\"column\">\n {{ row[column.key] }}\n</ng-template>\n<ng-template\n #transformData\n let-row=\"row\"\n let-column=\"column\"\n let-transform=\"transform\"\n let-data=\"data\"\n>\n {{ row[column.key] | dynamicPipe: transform.pipe:transform?.args }}\n</ng-template>\n<ng-template #transformFooter let-value=\"value\" let-transform=\"transform\">\n {{\n (value | dynamicPipe: transform.pipe:transform?.args) ||\n (tableConfig$ | async)?.footer?.emptyContent\n }}\n</ng-template>\n<ng-template #rawFooter let-value=\"value\">\n {{ value || (tableConfig$ | async)?.footer?.emptyContent }}\n</ng-template>\n<ng-template\n #templateRef\n let-row=\"row\"\n let-column=\"column\"\n let-index=\"index\"\n let-templateRef=\"templateRef\"\n let-data=\"data\"\n>\n <ng-container\n [ngTemplateOutlet]=\"templateRef\"\n [ngTemplateOutletContext]=\"{\n row: row,\n col: column,\n index: index,\n data: data\n }\"\n ></ng-container>\n</ng-template>\n", dependencies: [{ kind: "pipe", type: CapitalCasePipe, name: "capitalCase" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: SortClassPipe, name: "sortClass" }, { kind: "pipe", type: DashCasePipe, name: "dashCase" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: SlicePipe, name: "slice" }, { kind: "pipe", type: DynamicPipe, name: "dynamicPipe" }, { kind: "pipe", type: HighlightPipe, name: "highlight" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
840
+ CoreComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.1", type: CoreComponent, isStandalone: true, selector: "angular-generic-table", inputs: { navigationKeys: "navigationKeys", selectKeys: "selectKeys", loading: "loading", paginationIndex: "paginationIndex", pagingInfo: "pagingInfo", customClasses: "customClasses", isRowSelectedFn: "isRowSelectedFn", selection: "selection", rowIdKey: "rowIdKey", generateRowId: "generateRowId", trackRowByFn: "trackRowByFn", search: "search", config: "config", data: "data", sortOrder: "sortOrder" }, outputs: { rowClick: "rowClick", rowSelect: "rowSelect", sortOrderChange: "sortOrderChange", rowActive: "rowActive", columnSort: "columnSort", pageChange: "pageChange" }, ngImport: i0, template: "<table\n [ngClass]=\"(tableConfig$ | async)?.class || 'table'\"\n [class.table-mobile]=\"(tableConfig$ | async)?.mobileLayout\"\n [class.table-horizontal]=\"(tableConfig$ | async)?.rows\"\n [class.table-loading]=\"loading$ | async\"\n [class.gt-sticky-row-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.row && (tableConfig$ | async)?.rows\n \"\n [class.gt-sticky-column-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.column\n \"\n [attr.aria-busy]=\"(loading$ | async) === true ? true : null\"\n [tabindex]=\"(tableConfig$ | async)?.activateRowOnKeyboardNavigation ? 0 : -1\"\n #tableRef\n (focus)=\"listenToKeyboardEvents()\"\n (focusout)=\"unsubscribeFromKeyboardEvents(tableRef)\"\n (mouseenter)=\"listenToKeyboardEvents()\"\n (mouseleave)=\"unsubscribeFromKeyboardEvents(tableRef)\"\n>\n <thead>\n <tr\n *ngIf=\"{\n config: (tableConfig$ | async)!,\n isLoading: loading$ | async\n } as table\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <th\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [class.disabled]=\"table.isLoading\"\n [attr.aria-sort]=\"sortOrder$ | async | sortClass: column.key:'aria'\"\n [class.gt-sortable]=\"true\"\n scope=\"col\"\n >\n <button\n *ngIf=\"column.value?.sortable\"\n [attr.data-sort-order]=\"\n sortOrder$ | async | sortClass: column.key:'order'\n \"\n class=\"gt-sort\"\n (click)=\"\n table.isLoading ||\n !column.value.sortable ||\n sortByKey(column.key, $event)\n \"\n >\n <span *ngIf=\"column.value?.header !== false\">{{\n column.value.header || column.key | capitalCase\n }}</span>\n </button>\n <span\n *ngIf=\"!column.value?.sortable && column.value?.header !== false\"\n >{{ column.value.header || column.key | capitalCase }}</span\n >\n </th>\n </ng-container>\n <ng-container\n *ngIf=\"\n ((table?.config?.rows | keyvalue: columnOrder) || [])[0] as headerRow\n \"\n >\n <th\n class=\"row-header\"\n [attr.aria-sort]=\"\n sortOrder$ | async | sortClass: headerRow.key:'aria'\n \"\n ngClass=\"{{ headerRow.value.sortable ? 'sort ' : '' }} {{\n sortOrder$ | async | sortClass: headerRow.key\n }} {{ (headerRow.key | dashCase) + '-column' }}\"\n (click)=\"\n table.isLoading ||\n !headerRow.value.sortable ||\n sortByKey(headerRow.key, $event)\n \"\n scope=\"col\"\n >\n <ng-container *ngIf=\"headerRow?.value?.header !== false\">{{\n headerRow?.value?.header || headerRow.key | capitalCase\n }}</ng-container>\n </th>\n <th\n *ngFor=\"let column of ((table$ | async)?.data || [])[0]\"\n ngClass=\"{{ headerRow.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[headerRow.key].templateRef\n ? templateRef\n : (table.config.rows || {})[headerRow.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: headerRow,\n transform: (table.config.rows || {})[headerRow.key].transform,\n templateRef: (table.config.rows || {})[headerRow.key].templateRef,\n index: 0\n }\"\n >\n </ng-container>\n </th>\n </ng-container>\n </tr>\n </thead>\n <tbody *ngIf=\"loading$ | async; else tableContent\">\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-loading\"></ng-content>\n </td>\n </tr>\n </tbody>\n <tfoot *ngIf=\"(table$ | async)! as table\">\n <ng-container *ngIf=\"table.data.length > 0 && !(loading$ | async)\">\n <ng-container *ngIf=\"(calculations$ | async)! as calculations\">\n <tr\n *ngFor=\"let calculation of calculations.calculations; let i = index\"\n >\n <ng-container\n *ngIf=\"{\n showHeader: (colspan$ | async) !== (footerColspan$ | async)\n } as footerRow\"\n >\n <th\n *ngIf=\"footerRow.showHeader\"\n [colSpan]=\"\n ((colspan$ | async) || 0) - ((footerColspan$ | async) || 0)\n \"\n scope=\"row\"\n >\n <ng-container\n *ngIf=\"table.config?.footer?.headers?.[calculation] as showHeader\"\n >{{showHeader === true ? (calculation | capitalCase): table.config.footer?.headers?.[calculation]}}\n </ng-container>\n </th>\n <ng-container\n *ngFor=\"\n let column of table.config?.columns | keyvalue: columnOrder\n \"\n >\n <td\n *ngIf=\"\n !column.value?.hidden && calculations.calculated[column.key]\n \"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-header]=\"\n !footerRow.showHeader && table.config.footer?.headers?.[calculation]\n ? table.config.footer?.headers?.[calculation] === true ? (calculation | capitalCase) : table.config.footer?.headers?.[calculation]\n : null\n \"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n [class.gt-no-content]=\"\n !calculations.calculated[column.key][calculation]\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformFooter\n : rawFooter\n \"\n [ngTemplateOutletContext]=\"{\n value: calculations.calculated[column.key][calculation],\n row: calculations.calculated[column.key],\n column: calculation,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n transform: (table.config.columns || {})[column.key]\n .transform\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </ng-container>\n </tr>\n </ng-container>\n </ng-container>\n </tfoot>\n</table>\n<ng-template #tableContent>\n <ng-container *ngIf=\"(table$ | async)! as table\">\n <tbody *ngIf=\"(table!.data![0] || table!.data!).length > 0; else noData\">\n <ng-container *ngIf=\"table.config.columns\">\n <tr\n *ngFor=\"\n let row of table!.data![\n table.info.lazyLoaded ? 0 : (currentPaginationIndex$ | async) || 0\n ];\n trackBy: trackRowByFn;\n let i = index\n \"\n [attr.id]=\"'tableRow_' + i\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseenter)=\"\n table?.config?.activateRowOnHover && _activateRow(row, i, $event)\n \"\n (mouseleave)=\"\n table?.config?.activateRowOnHover &&\n _activateRow(null, null, $event)\n \"\n [ngClass]=\"[\n !!isRowSelectedFn\n ? (row\n | rowSelection\n : selection\n : isRowSelectedFn\n : customClasses.selectedRow)\n : '',\n (rowActive$ | async)?.index === i ? customClasses.activeRow : ''\n ]\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <td\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (searchBy$ | async) &&\n !(table.config.columns || {})[column.key].templateRef\n ? highlighted\n : (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: row,\n column: column,\n search: (searchBy$ | async),\n transform: (table.config.columns || {})[column.key].transform,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n index: i,\n data: table.data[\n table.info.lazyLoaded\n ? 0\n : (currentPaginationIndex$ | async) || 0\n ]\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </tr>\n </ng-container>\n <ng-container *ngIf=\"table.config.rows\">\n <ng-container\n *ngFor=\"\n let row of table?.config?.rows | keyvalue: columnOrder | slice: 1;\n let i = index\n \"\n >\n <tr\n *ngIf=\"!row.value?.hidden\"\n [attr.id]=\"'tableRow_' + i\"\n ngClass=\"{{ (row.key | dashCase) + '-row' }}\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseenter)=\"\n table?.config?.activateRowOnHover && _activateRow(row, i, $event)\n \"\n (mouseleave)=\"\n table?.config?.activateRowOnHover &&\n _activateRow(null, null, $event)\n \"\n [ngClass]=\"[\n !!isRowSelectedFn\n ? (row\n | rowSelection\n : selection\n : isRowSelectedFn\n : customClasses.selectedRow)\n : '',\n (rowActive$ | async)?.index === i ? customClasses.activeRow : ''\n ]\"\n >\n <th class=\"row-header\" scope=\"row\">\n {{ row.value.header || row.key | capitalCase }}\n </th>\n <td\n *ngFor=\"let column of (table?.data || [])[0]; let y = index\"\n ngClass=\"{{ row.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[row.key].templateRef\n ? templateRef\n : (table.config.rows || {})[row.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: row,\n transform: (table.config.rows || {})[row.key].transform,\n templateRef: (table.config.rows || {})[row.key].templateRef,\n index: table.config.rows ? y : i,\n data: table.data[\n table.info.lazyLoaded\n ? 0\n : (currentPaginationIndex$ | async) || 0\n ]\n }\"\n >\n </ng-container>\n </td>\n </tr>\n </ng-container>\n </ng-container>\n </tbody>\n </ng-container>\n</ng-template>\n<ng-template #noData>\n <tbody>\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-no-data\"></ng-content>\n </td>\n </tr>\n </tbody>\n</ng-template>\n<ng-template\n #highlighted\n let-row=\"row\"\n let-column=\"column\"\n let-search=\"search\"\n let-transform=\"transform\"\n>\n <div\n *ngIf=\"!transform\"\n [innerHTML]=\"row[column.key] | highlight: search\"\n ></div>\n <div\n *ngIf=\"transform\"\n [innerHTML]=\"\n row[column.key]\n | dynamicPipe: transform.pipe:transform?.args\n | highlight: search\n \"\n ></div>\n</ng-template>\n<ng-template #rawData let-row=\"row\" let-column=\"column\">\n {{ row[column.key] }}\n</ng-template>\n<ng-template\n #transformData\n let-row=\"row\"\n let-column=\"column\"\n let-transform=\"transform\"\n let-data=\"data\"\n>\n {{ row[column.key] | dynamicPipe: transform.pipe:transform?.args }}\n</ng-template>\n<ng-template #transformFooter let-value=\"value\" let-transform=\"transform\">\n {{\n (value | dynamicPipe: transform.pipe:transform?.args) ||\n (tableConfig$ | async)?.footer?.emptyContent\n }}\n</ng-template>\n<ng-template #rawFooter let-value=\"value\">\n {{ value || (tableConfig$ | async)?.footer?.emptyContent }}\n</ng-template>\n<ng-template\n #templateRef\n let-row=\"row\"\n let-column=\"column\"\n let-index=\"index\"\n let-templateRef=\"templateRef\"\n let-data=\"data\"\n>\n <ng-container\n [ngTemplateOutlet]=\"templateRef\"\n [ngTemplateOutletContext]=\"{\n row: row,\n col: column,\n index: index,\n data: data\n }\"\n ></ng-container>\n</ng-template>\n", dependencies: [{ kind: "pipe", type: CapitalCasePipe, name: "capitalCase" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: SortClassPipe, name: "sortClass" }, { kind: "pipe", type: DashCasePipe, name: "dashCase" }, { kind: "pipe", type: RowSelectionPipe, name: "rowSelection" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: SlicePipe, name: "slice" }, { kind: "pipe", type: DynamicPipe, name: "dynamicPipe" }, { kind: "pipe", type: HighlightPipe, name: "highlight" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
518
841
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CoreComponent, decorators: [{
519
842
  type: Component,
520
843
  args: [{ selector: 'angular-generic-table', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
@@ -522,6 +845,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImpor
522
845
  KeyValuePipe,
523
846
  SortClassPipe,
524
847
  DashCasePipe,
848
+ RowSelectionPipe,
525
849
  AsyncPipe,
526
850
  NgTemplateOutlet,
527
851
  SlicePipe,
@@ -530,10 +854,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImpor
530
854
  NgClass,
531
855
  NgIf,
532
856
  NgForOf,
533
- ], template: "<table\n [ngClass]=\"(tableConfig$ | async)?.class || 'table'\"\n [class.table-mobile]=\"(tableConfig$ | async)?.mobileLayout\"\n [class.table-horizontal]=\"(tableConfig$ | async)?.rows\"\n [class.table-loading]=\"loading$ | async\"\n [class.gt-sticky-row-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.row && (tableConfig$ | async)?.rows\n \"\n [class.gt-sticky-column-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.column\n \"\n [attr.aria-busy]=\"(loading$ | async) === true ? true : null\"\n>\n <thead>\n <tr\n *ngIf=\"{\n config: (tableConfig$ | async)!,\n isLoading: loading$ | async\n } as table\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <th\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [class.disabled]=\"table.isLoading\"\n [attr.aria-sort]=\"sortOrder$ | async | sortClass: column.key:'aria'\"\n [class.gt-sortable]=\"true\"\n scope=\"col\"\n >\n <button\n *ngIf=\"column.value?.sortable\"\n [attr.data-sort-order]=\"\n sortOrder$ | async | sortClass: column.key:'order'\n \"\n class=\"gt-sort\"\n (click)=\"\n table.isLoading ||\n !column.value.sortable ||\n sortByKey(column.key, $event)\n \"\n >\n <span *ngIf=\"column.value?.header !== false\">{{\n column.value.header || column.key | capitalCase\n }}</span>\n </button>\n <span\n *ngIf=\"!column.value?.sortable && column.value?.header !== false\"\n >{{ column.value.header || column.key | capitalCase }}</span\n >\n </th>\n </ng-container>\n <ng-container\n *ngIf=\"\n ((table?.config?.rows | keyvalue: columnOrder) || [])[0] as headerRow\n \"\n >\n <th\n class=\"row-header\"\n [attr.aria-sort]=\"\n sortOrder$ | async | sortClass: headerRow.key:'aria'\n \"\n ngClass=\"{{ headerRow.value.sortable ? 'sort ' : '' }} {{\n sortOrder$ | async | sortClass: headerRow.key\n }} {{ (headerRow.key | dashCase) + '-column' }}\"\n (click)=\"\n table.isLoading ||\n !headerRow.value.sortable ||\n sortByKey(headerRow.key, $event)\n \"\n scope=\"col\"\n >\n <ng-container *ngIf=\"headerRow?.value?.header !== false\">{{\n headerRow?.value?.header || headerRow.key | capitalCase\n }}</ng-container>\n </th>\n <th\n *ngFor=\"let column of ((table$ | async)?.data || [])[0]\"\n ngClass=\"{{ headerRow.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[headerRow.key].templateRef\n ? templateRef\n : (table.config.rows || {})[headerRow.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: headerRow,\n transform: (table.config.rows || {})[headerRow.key].transform,\n templateRef: (table.config.rows || {})[headerRow.key].templateRef,\n index: 0\n }\"\n >\n </ng-container>\n </th>\n </ng-container>\n </tr>\n </thead>\n <tbody *ngIf=\"loading$ | async; else tableContent\">\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-loading\"></ng-content>\n </td>\n </tr>\n </tbody>\n <tfoot *ngIf=\"(table$ | async)! as table\">\n <ng-container *ngIf=\"table.data.length > 0 && !(loading$ | async)\">\n <ng-container *ngIf=\"(calculations$ | async)! as calculations\">\n <tr\n *ngFor=\"let calculation of calculations.calculations; let i = index\"\n >\n <ng-container\n *ngIf=\"{\n showHeader: (colspan$ | async) !== (footerColspan$ | async)\n } as footerRow\"\n >\n <th\n *ngIf=\"footerRow.showHeader\"\n [colSpan]=\"\n ((colspan$ | async) || 0) - ((footerColspan$ | async) || 0)\n \"\n scope=\"row\"\n >\n <ng-container\n *ngIf=\"table.config?.footer?.headers?.[calculation] as showHeader\"\n >{{showHeader === true ? (calculation | capitalCase): table.config.footer?.headers?.[calculation]}}\n </ng-container>\n </th>\n <ng-container\n *ngFor=\"\n let column of table.config?.columns | keyvalue: columnOrder\n \"\n >\n <td\n *ngIf=\"\n !column.value?.hidden && calculations.calculated[column.key]\n \"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-header]=\"\n !footerRow.showHeader && table.config.footer?.headers?.[calculation]\n ? table.config.footer?.headers?.[calculation] === true ? (calculation | capitalCase) : table.config.footer?.headers?.[calculation]\n : null\n \"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n [class.gt-no-content]=\"\n !calculations.calculated[column.key][calculation]\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformFooter\n : rawFooter\n \"\n [ngTemplateOutletContext]=\"{\n value: calculations.calculated[column.key][calculation],\n row: calculations.calculated[column.key],\n column: calculation,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n transform: (table.config.columns || {})[column.key]\n .transform\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </ng-container>\n </tr>\n </ng-container>\n </ng-container>\n </tfoot>\n</table>\n<ng-template #tableContent>\n <ng-container *ngIf=\"(table$ | async)! as table\">\n <tbody *ngIf=\"(table!.data![0] || table!.data!).length > 0; else noData\">\n <ng-container *ngIf=\"table.config.columns\">\n <tr\n *ngFor=\"\n let row of table!.data![(currentPage$ | async) || 0];\n let i = index\n \"\n [attr.id]=\"'tableRow_' + i\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseover)=\"table?.config?.rowHover && _hoverRow(row, i, $event)\"\n (mouseout)=\"table?.config?.rowHover && _hoverRow(null, null, $event)\"\n [class.gt-hover]=\"(rowHover$ | async)?.index === i\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <td\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (searchBy$ | async) &&\n !(table.config.columns || {})[column.key].templateRef\n ? highlighted\n : (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: row,\n column: column,\n search: (searchBy$ | async),\n transform: (table.config.columns || {})[column.key].transform,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n index: i,\n data: table.data[(currentPage$ | async) || 0]\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </tr>\n </ng-container>\n <ng-container *ngIf=\"table.config.rows\">\n <ng-container\n *ngFor=\"\n let row of table?.config?.rows | keyvalue: columnOrder | slice: 1;\n let i = index\n \"\n >\n <tr\n *ngIf=\"!row.value?.hidden\"\n [attr.id]=\"'tableRow_' + i\"\n ngClass=\"{{ (row.key | dashCase) + '-row' }}\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseover)=\"table?.config?.rowHover && _hoverRow(row, i, $event)\"\n (mouseout)=\"\n table?.config?.rowHover && _hoverRow(null, null, $event)\n \"\n [class.gt-hover]=\"(rowHover$ | async)?.index === i\"\n >\n <th class=\"row-header\" scope=\"row\">\n {{ row.value.header || row.key | capitalCase }}\n </th>\n <td\n *ngFor=\"let column of (table?.data || [])[0]; let y = index\"\n ngClass=\"{{ row.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[row.key].templateRef\n ? templateRef\n : (table.config.rows || {})[row.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: row,\n transform: (table.config.rows || {})[row.key].transform,\n templateRef: (table.config.rows || {})[row.key].templateRef,\n index: table.config.rows ? y : i,\n data: table.data[(currentPage$ | async) || 0]\n }\"\n >\n </ng-container>\n </td>\n </tr>\n </ng-container>\n </ng-container>\n </tbody>\n </ng-container>\n</ng-template>\n<ng-template #noData>\n <tbody>\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-no-data\"></ng-content>\n </td>\n </tr>\n </tbody>\n</ng-template>\n<ng-template\n #highlighted\n let-row=\"row\"\n let-column=\"column\"\n let-search=\"search\"\n let-transform=\"transform\"\n>\n <div\n *ngIf=\"!transform\"\n [innerHTML]=\"row[column.key] | highlight: search\"\n ></div>\n <div\n *ngIf=\"transform\"\n [innerHTML]=\"\n row[column.key]\n | dynamicPipe: transform.pipe:transform?.args\n | highlight: search\n \"\n ></div>\n</ng-template>\n<ng-template #rawData let-row=\"row\" let-column=\"column\">\n {{ row[column.key] }}\n</ng-template>\n<ng-template\n #transformData\n let-row=\"row\"\n let-column=\"column\"\n let-transform=\"transform\"\n let-data=\"data\"\n>\n {{ row[column.key] | dynamicPipe: transform.pipe:transform?.args }}\n</ng-template>\n<ng-template #transformFooter let-value=\"value\" let-transform=\"transform\">\n {{\n (value | dynamicPipe: transform.pipe:transform?.args) ||\n (tableConfig$ | async)?.footer?.emptyContent\n }}\n</ng-template>\n<ng-template #rawFooter let-value=\"value\">\n {{ value || (tableConfig$ | async)?.footer?.emptyContent }}\n</ng-template>\n<ng-template\n #templateRef\n let-row=\"row\"\n let-column=\"column\"\n let-index=\"index\"\n let-templateRef=\"templateRef\"\n let-data=\"data\"\n>\n <ng-container\n [ngTemplateOutlet]=\"templateRef\"\n [ngTemplateOutletContext]=\"{\n row: row,\n col: column,\n index: index,\n data: data\n }\"\n ></ng-container>\n</ng-template>\n" }]
534
- }], propDecorators: { loading: [{
857
+ ], template: "<table\n [ngClass]=\"(tableConfig$ | async)?.class || 'table'\"\n [class.table-mobile]=\"(tableConfig$ | async)?.mobileLayout\"\n [class.table-horizontal]=\"(tableConfig$ | async)?.rows\"\n [class.table-loading]=\"loading$ | async\"\n [class.gt-sticky-row-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.row && (tableConfig$ | async)?.rows\n \"\n [class.gt-sticky-column-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.column\n \"\n [attr.aria-busy]=\"(loading$ | async) === true ? true : null\"\n [tabindex]=\"(tableConfig$ | async)?.activateRowOnKeyboardNavigation ? 0 : -1\"\n #tableRef\n (focus)=\"listenToKeyboardEvents()\"\n (focusout)=\"unsubscribeFromKeyboardEvents(tableRef)\"\n (mouseenter)=\"listenToKeyboardEvents()\"\n (mouseleave)=\"unsubscribeFromKeyboardEvents(tableRef)\"\n>\n <thead>\n <tr\n *ngIf=\"{\n config: (tableConfig$ | async)!,\n isLoading: loading$ | async\n } as table\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <th\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [class.disabled]=\"table.isLoading\"\n [attr.aria-sort]=\"sortOrder$ | async | sortClass: column.key:'aria'\"\n [class.gt-sortable]=\"true\"\n scope=\"col\"\n >\n <button\n *ngIf=\"column.value?.sortable\"\n [attr.data-sort-order]=\"\n sortOrder$ | async | sortClass: column.key:'order'\n \"\n class=\"gt-sort\"\n (click)=\"\n table.isLoading ||\n !column.value.sortable ||\n sortByKey(column.key, $event)\n \"\n >\n <span *ngIf=\"column.value?.header !== false\">{{\n column.value.header || column.key | capitalCase\n }}</span>\n </button>\n <span\n *ngIf=\"!column.value?.sortable && column.value?.header !== false\"\n >{{ column.value.header || column.key | capitalCase }}</span\n >\n </th>\n </ng-container>\n <ng-container\n *ngIf=\"\n ((table?.config?.rows | keyvalue: columnOrder) || [])[0] as headerRow\n \"\n >\n <th\n class=\"row-header\"\n [attr.aria-sort]=\"\n sortOrder$ | async | sortClass: headerRow.key:'aria'\n \"\n ngClass=\"{{ headerRow.value.sortable ? 'sort ' : '' }} {{\n sortOrder$ | async | sortClass: headerRow.key\n }} {{ (headerRow.key | dashCase) + '-column' }}\"\n (click)=\"\n table.isLoading ||\n !headerRow.value.sortable ||\n sortByKey(headerRow.key, $event)\n \"\n scope=\"col\"\n >\n <ng-container *ngIf=\"headerRow?.value?.header !== false\">{{\n headerRow?.value?.header || headerRow.key | capitalCase\n }}</ng-container>\n </th>\n <th\n *ngFor=\"let column of ((table$ | async)?.data || [])[0]\"\n ngClass=\"{{ headerRow.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[headerRow.key].templateRef\n ? templateRef\n : (table.config.rows || {})[headerRow.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: headerRow,\n transform: (table.config.rows || {})[headerRow.key].transform,\n templateRef: (table.config.rows || {})[headerRow.key].templateRef,\n index: 0\n }\"\n >\n </ng-container>\n </th>\n </ng-container>\n </tr>\n </thead>\n <tbody *ngIf=\"loading$ | async; else tableContent\">\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-loading\"></ng-content>\n </td>\n </tr>\n </tbody>\n <tfoot *ngIf=\"(table$ | async)! as table\">\n <ng-container *ngIf=\"table.data.length > 0 && !(loading$ | async)\">\n <ng-container *ngIf=\"(calculations$ | async)! as calculations\">\n <tr\n *ngFor=\"let calculation of calculations.calculations; let i = index\"\n >\n <ng-container\n *ngIf=\"{\n showHeader: (colspan$ | async) !== (footerColspan$ | async)\n } as footerRow\"\n >\n <th\n *ngIf=\"footerRow.showHeader\"\n [colSpan]=\"\n ((colspan$ | async) || 0) - ((footerColspan$ | async) || 0)\n \"\n scope=\"row\"\n >\n <ng-container\n *ngIf=\"table.config?.footer?.headers?.[calculation] as showHeader\"\n >{{showHeader === true ? (calculation | capitalCase): table.config.footer?.headers?.[calculation]}}\n </ng-container>\n </th>\n <ng-container\n *ngFor=\"\n let column of table.config?.columns | keyvalue: columnOrder\n \"\n >\n <td\n *ngIf=\"\n !column.value?.hidden && calculations.calculated[column.key]\n \"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-header]=\"\n !footerRow.showHeader && table.config.footer?.headers?.[calculation]\n ? table.config.footer?.headers?.[calculation] === true ? (calculation | capitalCase) : table.config.footer?.headers?.[calculation]\n : null\n \"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n [class.gt-no-content]=\"\n !calculations.calculated[column.key][calculation]\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformFooter\n : rawFooter\n \"\n [ngTemplateOutletContext]=\"{\n value: calculations.calculated[column.key][calculation],\n row: calculations.calculated[column.key],\n column: calculation,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n transform: (table.config.columns || {})[column.key]\n .transform\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </ng-container>\n </tr>\n </ng-container>\n </ng-container>\n </tfoot>\n</table>\n<ng-template #tableContent>\n <ng-container *ngIf=\"(table$ | async)! as table\">\n <tbody *ngIf=\"(table!.data![0] || table!.data!).length > 0; else noData\">\n <ng-container *ngIf=\"table.config.columns\">\n <tr\n *ngFor=\"\n let row of table!.data![\n table.info.lazyLoaded ? 0 : (currentPaginationIndex$ | async) || 0\n ];\n trackBy: trackRowByFn;\n let i = index\n \"\n [attr.id]=\"'tableRow_' + i\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseenter)=\"\n table?.config?.activateRowOnHover && _activateRow(row, i, $event)\n \"\n (mouseleave)=\"\n table?.config?.activateRowOnHover &&\n _activateRow(null, null, $event)\n \"\n [ngClass]=\"[\n !!isRowSelectedFn\n ? (row\n | rowSelection\n : selection\n : isRowSelectedFn\n : customClasses.selectedRow)\n : '',\n (rowActive$ | async)?.index === i ? customClasses.activeRow : ''\n ]\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <td\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (searchBy$ | async) &&\n !(table.config.columns || {})[column.key].templateRef\n ? highlighted\n : (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: row,\n column: column,\n search: (searchBy$ | async),\n transform: (table.config.columns || {})[column.key].transform,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n index: i,\n data: table.data[\n table.info.lazyLoaded\n ? 0\n : (currentPaginationIndex$ | async) || 0\n ]\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </tr>\n </ng-container>\n <ng-container *ngIf=\"table.config.rows\">\n <ng-container\n *ngFor=\"\n let row of table?.config?.rows | keyvalue: columnOrder | slice: 1;\n let i = index\n \"\n >\n <tr\n *ngIf=\"!row.value?.hidden\"\n [attr.id]=\"'tableRow_' + i\"\n ngClass=\"{{ (row.key | dashCase) + '-row' }}\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseenter)=\"\n table?.config?.activateRowOnHover && _activateRow(row, i, $event)\n \"\n (mouseleave)=\"\n table?.config?.activateRowOnHover &&\n _activateRow(null, null, $event)\n \"\n [ngClass]=\"[\n !!isRowSelectedFn\n ? (row\n | rowSelection\n : selection\n : isRowSelectedFn\n : customClasses.selectedRow)\n : '',\n (rowActive$ | async)?.index === i ? customClasses.activeRow : ''\n ]\"\n >\n <th class=\"row-header\" scope=\"row\">\n {{ row.value.header || row.key | capitalCase }}\n </th>\n <td\n *ngFor=\"let column of (table?.data || [])[0]; let y = index\"\n ngClass=\"{{ row.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[row.key].templateRef\n ? templateRef\n : (table.config.rows || {})[row.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: row,\n transform: (table.config.rows || {})[row.key].transform,\n templateRef: (table.config.rows || {})[row.key].templateRef,\n index: table.config.rows ? y : i,\n data: table.data[\n table.info.lazyLoaded\n ? 0\n : (currentPaginationIndex$ | async) || 0\n ]\n }\"\n >\n </ng-container>\n </td>\n </tr>\n </ng-container>\n </ng-container>\n </tbody>\n </ng-container>\n</ng-template>\n<ng-template #noData>\n <tbody>\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-no-data\"></ng-content>\n </td>\n </tr>\n </tbody>\n</ng-template>\n<ng-template\n #highlighted\n let-row=\"row\"\n let-column=\"column\"\n let-search=\"search\"\n let-transform=\"transform\"\n>\n <div\n *ngIf=\"!transform\"\n [innerHTML]=\"row[column.key] | highlight: search\"\n ></div>\n <div\n *ngIf=\"transform\"\n [innerHTML]=\"\n row[column.key]\n | dynamicPipe: transform.pipe:transform?.args\n | highlight: search\n \"\n ></div>\n</ng-template>\n<ng-template #rawData let-row=\"row\" let-column=\"column\">\n {{ row[column.key] }}\n</ng-template>\n<ng-template\n #transformData\n let-row=\"row\"\n let-column=\"column\"\n let-transform=\"transform\"\n let-data=\"data\"\n>\n {{ row[column.key] | dynamicPipe: transform.pipe:transform?.args }}\n</ng-template>\n<ng-template #transformFooter let-value=\"value\" let-transform=\"transform\">\n {{\n (value | dynamicPipe: transform.pipe:transform?.args) ||\n (tableConfig$ | async)?.footer?.emptyContent\n }}\n</ng-template>\n<ng-template #rawFooter let-value=\"value\">\n {{ value || (tableConfig$ | async)?.footer?.emptyContent }}\n</ng-template>\n<ng-template\n #templateRef\n let-row=\"row\"\n let-column=\"column\"\n let-index=\"index\"\n let-templateRef=\"templateRef\"\n let-data=\"data\"\n>\n <ng-container\n [ngTemplateOutlet]=\"templateRef\"\n [ngTemplateOutletContext]=\"{\n row: row,\n col: column,\n index: index,\n data: data\n }\"\n ></ng-container>\n</ng-template>\n" }]
858
+ }], propDecorators: { navigationKeys: [{
859
+ type: Input
860
+ }], selectKeys: [{
861
+ type: Input
862
+ }], loading: [{
863
+ type: Input
864
+ }], paginationIndex: [{
865
+ type: Input
866
+ }], pagingInfo: [{
867
+ type: Input
868
+ }], customClasses: [{
535
869
  type: Input
536
- }], page: [{
870
+ }], isRowSelectedFn: [{
871
+ type: Input
872
+ }], selection: [{
873
+ type: Input
874
+ }], rowIdKey: [{
875
+ type: Input
876
+ }], generateRowId: [{
877
+ type: Input
878
+ }], trackRowByFn: [{
537
879
  type: Input
538
880
  }], search: [{
539
881
  type: Input
@@ -545,13 +887,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImpor
545
887
  type: Input
546
888
  }], rowClick: [{
547
889
  type: Output
890
+ }], rowSelect: [{
891
+ type: Output
548
892
  }], sortOrderChange: [{
549
- type: Output,
550
- args: ['sortOrderChange']
551
- }], rowHover: [{
893
+ type: Output
894
+ }], rowActive: [{
552
895
  type: Output
553
896
  }], columnSort: [{
554
897
  type: Output
898
+ }], pageChange: [{
899
+ type: Output
555
900
  }] } });
556
901
 
557
902
  class GtDeltaComponent {
@@ -685,6 +1030,7 @@ GenericTableCoreModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0",
685
1030
  SortClassPipe,
686
1031
  DashCasePipe,
687
1032
  HighlightPipe,
1033
+ RowSelectionPipe,
688
1034
  CapitalCasePipe,
689
1035
  CapitalCasePipe,
690
1036
  DynamicPipe,
@@ -701,18 +1047,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImpor
701
1047
  SortClassPipe,
702
1048
  DashCasePipe,
703
1049
  HighlightPipe,
1050
+ RowSelectionPipe,
704
1051
  CapitalCasePipe,
705
1052
  CapitalCasePipe,
706
1053
  DynamicPipe,
707
1054
  GtDeltaComponent,
708
1055
  ],
709
1056
  exports: [CoreComponent, GtDeltaComponent],
1057
+ declarations: [],
710
1058
  }]
711
1059
  }] });
712
1060
 
713
1061
  class PaginationComponent {
714
1062
  constructor() {
715
- this.table$ = new ReplaySubject(1);
1063
+ this._table$ = new ReplaySubject(1);
716
1064
  this._ariaLabels = {
717
1065
  nav: 'Table pagination',
718
1066
  button: 'Go to page ',
@@ -723,58 +1071,111 @@ class PaginationComponent {
723
1071
  button: 'page-link',
724
1072
  };
725
1073
  this._paginationLength = 5;
726
- this.pagination$ = this.table$.pipe(switchMap((core) => combineLatest([core?.table$.pipe(pluck('info')), core?.currentPage$])), map(([info, currentPage]) => this.generateList(info.pageTotal, currentPage)));
1074
+ /** paginationListItems$ - observable for page numbers to show based on number of pages and current position */
1075
+ this.paginationListItems$ = this._table$.pipe(switchMap((core) => combineLatest([
1076
+ core?.table$.pipe(pluck('info')),
1077
+ core?.currentPaginationIndex$,
1078
+ ])), map(([info, currentPage]) => this._generateList(info.pageTotal, currentPage)), shareReplay(1));
1079
+ }
1080
+ get pagingInfo() {
1081
+ return (this._pagingInfo || {
1082
+ pageNext: null,
1083
+ pageCurrent: null,
1084
+ pagePrevious: null,
1085
+ pageSize: null,
1086
+ numberOfRecords: null,
1087
+ pageTotal: null,
1088
+ });
1089
+ }
1090
+ /** pagingInfo
1091
+ * @description when provided, pagination component will use this information to render pagination instead of data from table. Use this option when pagination is handled by backend (server side).
1092
+ * @type info - metadata for pagination component
1093
+ */
1094
+ set pagingInfo(info) {
1095
+ this._pagingInfo = info;
727
1096
  }
728
1097
  get paginationLength() {
729
1098
  return this._paginationLength;
730
1099
  }
731
- set paginationLength(value) {
732
- this._paginationLength = +value;
1100
+ /** paginationLength
1101
+ * @description number of buttons to show in pagination
1102
+ * @type length - number of buttons to show. Defaults to: `5`
1103
+ */
1104
+ set paginationLength(length) {
1105
+ this._paginationLength = +length;
733
1106
  }
734
1107
  get classes() {
735
1108
  return this._classes;
736
1109
  }
737
- set classes(value) {
738
- this._classes = value;
1110
+ /** classes
1111
+ * @description classes that should be used within pagination component for different elements
1112
+ * @type classes - classes to be used. Defaults to: `{
1113
+ * ul: 'pagination',
1114
+ * li: 'page-item',
1115
+ * button: 'page-link',
1116
+ * }`
1117
+ */
1118
+ set classes(classes) {
1119
+ this._classes = classes;
739
1120
  }
740
1121
  get ariaLabels() {
741
1122
  return this._ariaLabels;
742
1123
  }
743
- set ariaLabels(value) {
744
- this._ariaLabels = value;
1124
+ /** ariaLabels
1125
+ * @description aria labels that describe pagination component
1126
+ * @type labels - aria labels for pagination. Defaults to: `{
1127
+ * nav: 'Table pagination',
1128
+ * button: 'Go to page ',
1129
+ * }`
1130
+ */
1131
+ set ariaLabels(labels) {
1132
+ this._ariaLabels = labels;
745
1133
  }
746
1134
  get table() {
747
1135
  return this._table;
748
1136
  }
749
- set table(value) {
750
- this._table = value;
751
- this.table$.next(value);
1137
+ /** table
1138
+ * @description table component to which pagination is attached
1139
+ * @type tableRef - table component
1140
+ */
1141
+ set table(tableRef) {
1142
+ this._table = tableRef;
1143
+ this._table$.next(tableRef);
752
1144
  }
753
- generateList(pages, currentPosition) {
1145
+ /** generate list - generate an array with page numbers to show based on number of pages and current position
1146
+ * @param numberOfPages number of pages to show
1147
+ * @param currentPosition current position (page index) being shown in table
1148
+ * @returns Array<number> array of page numbers to show
1149
+ */
1150
+ _generateList(numberOfPages, currentPosition) {
754
1151
  const middle = Math.floor(this.paginationLength / 2);
755
- const length = pages < this.paginationLength ? pages : this.paginationLength;
1152
+ const length = numberOfPages < this.paginationLength
1153
+ ? numberOfPages
1154
+ : this.paginationLength;
756
1155
  return Array.from({ length }, (_, i) => {
757
1156
  if (i === 0) {
758
1157
  return 1;
759
1158
  }
760
- else if (pages < this.paginationLength) {
1159
+ else if (numberOfPages < this.paginationLength) {
761
1160
  return i + 1;
762
1161
  }
763
1162
  else if (i + 1 === length) {
764
- return pages;
1163
+ return numberOfPages;
765
1164
  }
766
- else if (currentPosition > middle && currentPosition < pages - middle) {
1165
+ else if (currentPosition > middle &&
1166
+ currentPosition < numberOfPages - middle) {
767
1167
  return i + currentPosition - (middle - 1);
768
1168
  }
769
1169
  else if (currentPosition > middle &&
770
- currentPosition < pages - (middle - 1)) {
1170
+ currentPosition < numberOfPages - (middle - 1)) {
771
1171
  return i + currentPosition - middle;
772
1172
  }
773
1173
  else if (currentPosition > middle &&
774
- currentPosition === pages - (middle - 1)) {
1174
+ currentPosition === numberOfPages - (middle - 1)) {
775
1175
  return i + currentPosition - (middle + 1);
776
1176
  }
777
- else if (currentPosition > middle && currentPosition === pages - 1) {
1177
+ else if (currentPosition > middle &&
1178
+ currentPosition === numberOfPages - 1) {
778
1179
  return i + currentPosition - (middle + 2);
779
1180
  }
780
1181
  else {
@@ -782,18 +1183,23 @@ class PaginationComponent {
782
1183
  }
783
1184
  });
784
1185
  }
785
- goto(page) {
1186
+ /** go to page
1187
+ * @param index - page index to go to
1188
+ */
1189
+ goToPage(index) {
786
1190
  if (this.table) {
787
- this.table.page = page - 1;
1191
+ this.table.paginationIndex = index - 1;
788
1192
  }
789
1193
  }
790
1194
  }
791
1195
  PaginationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
792
- PaginationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.1", type: PaginationComponent, isStandalone: true, selector: "angular-generic-table-pagination", inputs: { paginationLength: "paginationLength", classes: "classes", ariaLabels: "ariaLabels", table: "table" }, ngImport: i0, template: "<ng-container\n *ngIf=\"{\n links: pagination$ | async,\n currentPosition: table?.currentPage$ | async\n } as pagination\"\n>\n <nav\n *ngIf=\"pagination.links && pagination.links.length > 1\"\n role=\"navigation\"\n [attr.aria-label]=\"ariaLabels.nav\"\n class=\"gt-pagination\"\n [class]=\"classes.nav\"\n >\n <ul [class]=\"classes.ul\">\n <ng-container\n *ngFor=\"\n let position of pagination!.links;\n let i = index;\n let last = last\n \"\n >\n <li\n [class]=\"classes.li\"\n [class.active]=\"position === (pagination!.currentPosition || 0) + 1\"\n >\n <button\n [class]=\"classes.button\"\n [attr.aria-label]=\"ariaLabels.button + position\"\n (click)=\"goto(position)\"\n >\n {{ position }}\n </button>\n </li>\n <li\n [class]=\"classes.li\"\n class=\"gt-ellipsis\"\n *ngIf=\"position + 1 !== pagination!.links![i + 1] && !last\"\n >\n <button [class]=\"classes.button\" disabled tabindex=\"-1\"></button>\n </li>\n </ng-container>\n </ul>\n </nav>\n</ng-container>\n", dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1196
+ PaginationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.1", type: PaginationComponent, isStandalone: true, selector: "angular-generic-table-pagination", inputs: { pagingInfo: "pagingInfo", paginationLength: "paginationLength", classes: "classes", ariaLabels: "ariaLabels", table: "table" }, ngImport: i0, template: "<ng-container\n *ngIf=\"{\n links: paginationListItems$ | async,\n currentPosition: table?.currentPaginationIndex$ | async\n } as pagination\"\n>\n <nav\n *ngIf=\"pagination.links && pagination.links.length > 1\"\n role=\"navigation\"\n [attr.aria-label]=\"ariaLabels.nav\"\n class=\"gt-pagination\"\n [class]=\"classes.nav\"\n >\n <ul [class]=\"classes.ul\">\n <ng-container\n *ngFor=\"\n let position of pagination!.links;\n let i = index;\n let last = last\n \"\n >\n <li\n [class]=\"classes.li\"\n [class.active]=\"position === (pagination!.currentPosition || 0) + 1\"\n >\n <button\n [class]=\"classes.button\"\n [attr.aria-label]=\"ariaLabels.button + position\"\n (click)=\"goToPage(position)\"\n >\n {{ position }}\n </button>\n </li>\n <li\n [class]=\"classes.li\"\n class=\"gt-ellipsis\"\n *ngIf=\"position + 1 !== pagination!.links![i + 1] && !last\"\n >\n <button [class]=\"classes.button\" disabled tabindex=\"-1\"></button>\n </li>\n </ng-container>\n </ul>\n </nav>\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
793
1197
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: PaginationComponent, decorators: [{
794
1198
  type: Component,
795
- args: [{ selector: 'angular-generic-table-pagination', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [AsyncPipe, NgIf, NgForOf], template: "<ng-container\n *ngIf=\"{\n links: pagination$ | async,\n currentPosition: table?.currentPage$ | async\n } as pagination\"\n>\n <nav\n *ngIf=\"pagination.links && pagination.links.length > 1\"\n role=\"navigation\"\n [attr.aria-label]=\"ariaLabels.nav\"\n class=\"gt-pagination\"\n [class]=\"classes.nav\"\n >\n <ul [class]=\"classes.ul\">\n <ng-container\n *ngFor=\"\n let position of pagination!.links;\n let i = index;\n let last = last\n \"\n >\n <li\n [class]=\"classes.li\"\n [class.active]=\"position === (pagination!.currentPosition || 0) + 1\"\n >\n <button\n [class]=\"classes.button\"\n [attr.aria-label]=\"ariaLabels.button + position\"\n (click)=\"goto(position)\"\n >\n {{ position }}\n </button>\n </li>\n <li\n [class]=\"classes.li\"\n class=\"gt-ellipsis\"\n *ngIf=\"position + 1 !== pagination!.links![i + 1] && !last\"\n >\n <button [class]=\"classes.button\" disabled tabindex=\"-1\"></button>\n </li>\n </ng-container>\n </ul>\n </nav>\n</ng-container>\n" }]
796
- }], propDecorators: { paginationLength: [{
1199
+ args: [{ selector: 'angular-generic-table-pagination', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule], template: "<ng-container\n *ngIf=\"{\n links: paginationListItems$ | async,\n currentPosition: table?.currentPaginationIndex$ | async\n } as pagination\"\n>\n <nav\n *ngIf=\"pagination.links && pagination.links.length > 1\"\n role=\"navigation\"\n [attr.aria-label]=\"ariaLabels.nav\"\n class=\"gt-pagination\"\n [class]=\"classes.nav\"\n >\n <ul [class]=\"classes.ul\">\n <ng-container\n *ngFor=\"\n let position of pagination!.links;\n let i = index;\n let last = last\n \"\n >\n <li\n [class]=\"classes.li\"\n [class.active]=\"position === (pagination!.currentPosition || 0) + 1\"\n >\n <button\n [class]=\"classes.button\"\n [attr.aria-label]=\"ariaLabels.button + position\"\n (click)=\"goToPage(position)\"\n >\n {{ position }}\n </button>\n </li>\n <li\n [class]=\"classes.li\"\n class=\"gt-ellipsis\"\n *ngIf=\"position + 1 !== pagination!.links![i + 1] && !last\"\n >\n <button [class]=\"classes.button\" disabled tabindex=\"-1\"></button>\n </li>\n </ng-container>\n </ul>\n </nav>\n</ng-container>\n" }]
1200
+ }], propDecorators: { pagingInfo: [{
1201
+ type: Input
1202
+ }], paginationLength: [{
797
1203
  type: Input
798
1204
  }], classes: [{
799
1205
  type: Input
@@ -824,5 +1230,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImpor
824
1230
  * Generated bundle index. Do not edit.
825
1231
  */
826
1232
 
827
- export { CoreComponent, CoreService, GenericTableCoreModule, GenericTablePaginationModule, GtDeltaComponent, PaginationComponent };
1233
+ export { CapitalCasePipe, CoreComponent, CoreService, DashCasePipe, DynamicPipe, GenericTableCoreModule, GenericTablePaginationModule, GtDeltaComponent, HighlightPipe, PaginationComponent, SortClassPipe, calculate, capitalize, chunk, dashed, parseSortOrderParams, search, sortOnMultipleKeys, sortOrderConfigToParam, sortOrderToParams };
828
1234
  //# sourceMappingURL=angular-generic-table-core.mjs.map