@fuentis/phoenix-ui 0.0.9-alpha.358 → 0.0.9-alpha.360

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.
@@ -2225,25 +2225,31 @@ class TableCaptionComponent {
2225
2225
  this.filtersForm = this.fb.group({});
2226
2226
  if (this.filters && Array.isArray(this.filters)) {
2227
2227
  for (const filter of this.filters) {
2228
- let defaultValue = null;
2228
+ const hasSelected = filter.selected !== undefined &&
2229
+ filter.selected !== null &&
2230
+ (!Array.isArray(filter.selected) || filter.selected.length > 0);
2231
+ let defaultValue;
2229
2232
  if (filter.type === 'multiselect') {
2230
- // Convert any {label, key} entries in `selected` to primitives (key)
2231
- if (Array.isArray(filter.selected) && filter.selected.length > 0) {
2232
- defaultValue = filter.selected.map((s) => s && typeof s === 'object' && 'key' in s ? s.key : s);
2233
+ if (hasSelected) {
2234
+ defaultValue = (Array.isArray(filter.selected) ? filter.selected : [filter.selected])
2235
+ .map((s) => (s && typeof s === 'object' && 'key' in s ? s.key : s));
2233
2236
  }
2234
2237
  else {
2235
- defaultValue = []; // multiselects default to empty arrays
2238
+ defaultValue = [];
2236
2239
  }
2237
2240
  }
2238
2241
  else {
2239
- defaultValue = null; // other control types can stay null
2242
+ defaultValue = hasSelected
2243
+ ? (filter.selected && typeof filter.selected === 'object' && 'key' in filter.selected
2244
+ ? filter.selected.key
2245
+ : filter.selected)
2246
+ : null;
2240
2247
  }
2241
2248
  this.filtersForm.addControl(filter.key, this.fb.control(defaultValue));
2242
2249
  }
2243
- // Emit initial state so parent can apply defaults (e.g., active: [false])
2250
+ // Emit initial state
2244
2251
  const initial = this.filtersForm.getRawValue();
2245
2252
  this.applyFiltersEvent.emit(initial);
2246
- // Re-emit on any change; parent will filter accordingly
2247
2253
  this.filtersForm.valueChanges
2248
2254
  .pipe(takeUntilDestroyed(this.dr))
2249
2255
  .subscribe((val) => this.applyFiltersEvent.emit(val));
@@ -2745,7 +2751,7 @@ class TableComponent {
2745
2751
  // Inputs
2746
2752
  set data(value) {
2747
2753
  this.originalData = value ?? [];
2748
- this.allData = [...this.originalData];
2754
+ this.allData = [...value];
2749
2755
  this.totalRecords = this.allData.length;
2750
2756
  this.loadLazyData({ first: 0, rows: 100 });
2751
2757
  }
@@ -2765,37 +2771,41 @@ class TableComponent {
2765
2771
  allData = [];
2766
2772
  originalData = [];
2767
2773
  tableData = [];
2768
- selectedItems = signal([]); // ⬅️ back to signal
2774
+ selectedItems = signal([]);
2769
2775
  selectedColumns = [];
2770
2776
  searchQuery = '';
2771
2777
  bulkMode = false;
2772
2778
  totalRecords = 0;
2773
2779
  lastLoadedIndex = 0;
2774
- // Enums & helpers
2775
2780
  selectionTypeEnum = tableSelectionType;
2776
2781
  columnTypeEnum = tableColumnType;
2777
2782
  dateFormat;
2778
2783
  currentFilters = {};
2779
2784
  columnTypeMap = {};
2780
2785
  ngOnChanges(changes) {
2781
- // reset selection on input changes
2782
- this.selectedItems.set([]); // ⬅️ signal API
2783
- // (1) columns mapping + initial selectedColumns
2784
- if (this.columns?.length) {
2785
- this.selectedColumns = this.selectedColumnsInput?.length
2786
- ? [...this.selectedColumnsInput]
2787
- : [...this.columns];
2786
+ // reset selection
2787
+ this.selectedItems.set([]);
2788
+ // 1) mapiranje kolona i (odloženo) postavljanje selectedColumns
2789
+ if (this.columns?.length > 0) {
2790
+ // map za sortiranje/eksport
2788
2791
  this.columnTypeMap = {};
2789
2792
  for (const col of this.columns) {
2790
2793
  this.columnTypeMap[col.field] = col.columnType;
2791
2794
  }
2795
+ const nextSelected = this.selectedColumnsInput?.length ? this.selectedColumnsInput : this.columns;
2796
+ // ⬇️ Odloženo postavljanje reference (sprečava NG0100)
2797
+ Promise.resolve().then(() => {
2798
+ this.selectedColumns = [...nextSelected];
2799
+ this.cdr.markForCheck();
2800
+ });
2792
2801
  }
2793
- // (2) default More actions if not provided
2802
+ // 2) default moreActions (takođe odloženo da ne menja vrednost tokom istog CD pasa)
2794
2803
  if (!this.tableConfiguration?.moreActions) {
2795
- this.tableConfiguration = {
2796
- ...this.tableConfiguration,
2797
- moreActions: DEFAULT_MORE_ACTIONS,
2798
- };
2804
+ const cfg = this.tableConfiguration;
2805
+ Promise.resolve().then(() => {
2806
+ this.tableConfiguration = { ...cfg, moreActions: DEFAULT_MORE_ACTIONS };
2807
+ this.cdr.markForCheck();
2808
+ });
2799
2809
  }
2800
2810
  }
2801
2811
  // Lazy load / sort
@@ -2818,7 +2828,8 @@ class TableComponent {
2818
2828
  return 0;
2819
2829
  });
2820
2830
  }
2821
- this.tableData = sortedData.slice(first, first + rows);
2831
+ const paged = sortedData.slice(first, first + rows);
2832
+ this.tableData = sortedData; // (ako hoćeš paging, stavi paged)
2822
2833
  this.lastLoadedIndex = first + rows;
2823
2834
  }
2824
2835
  getComparableValue(val, field) {
@@ -2829,8 +2840,8 @@ class TableComponent {
2829
2840
  return val;
2830
2841
  if (typeof val === 'string') {
2831
2842
  if (columnType === this.columnTypeEnum.DATE) {
2832
- const parsed = Date.parse(val);
2833
- return isNaN(parsed) ? val.toLowerCase() : parsed;
2843
+ const parsedDate = Date.parse(val);
2844
+ return isNaN(parsedDate) ? val.toLowerCase() : parsedDate;
2834
2845
  }
2835
2846
  return val.toLowerCase();
2836
2847
  }
@@ -2845,10 +2856,10 @@ class TableComponent {
2845
2856
  if (Array.isArray(val) && val.length > 0) {
2846
2857
  return this.getComparableValue(val[0], field);
2847
2858
  }
2848
- const priority = ['name', 'value', 'label', 'key', 'date'];
2849
- for (const k of priority) {
2850
- if (val[k] !== undefined && val[k] !== null) {
2851
- return this.getComparableValue(val[k], field);
2859
+ const priorityFields = ['name', 'value', 'label', 'key', 'date'];
2860
+ for (const key of priorityFields) {
2861
+ if (val[key] !== undefined && val[key] !== null) {
2862
+ return this.getComparableValue(val[key], field);
2852
2863
  }
2853
2864
  }
2854
2865
  for (const v of Object.values(val)) {
@@ -2863,33 +2874,39 @@ class TableComponent {
2863
2874
  onSearch(query) {
2864
2875
  const trimmed = (query ?? '').trim().toLowerCase();
2865
2876
  this.searchQuery = trimmed;
2866
- const base = Object.keys(this.currentFilters).length > 0
2877
+ const baseData = Object.keys(this.currentFilters).length > 0
2867
2878
  ? this.getFilteredData()
2868
2879
  : this.originalData;
2869
2880
  if (trimmed) {
2870
- this.allData = base.filter((item) => Object.values(item).some((value) => this.matchesQuery(value, trimmed)));
2881
+ const filtered = baseData.filter((item) => Object.values(item).some((value) => this.matchesQuery(value, trimmed)));
2882
+ this.allData = filtered;
2871
2883
  }
2872
2884
  else {
2873
- this.allData = [...base];
2885
+ this.allData = [...baseData];
2874
2886
  }
2875
2887
  this.totalRecords = this.allData.length;
2876
2888
  this.loadLazyData({ first: 0, rows: 100 });
2877
2889
  }
2878
2890
  getFilteredData() {
2879
- return this.originalData.filter((item) => Object.keys(this.currentFilters).every((key) => {
2880
- const filterValue = this.currentFilters[key];
2881
- if (!filterValue || (Array.isArray(filterValue) && filterValue.length === 0))
2882
- return true;
2883
- const itemValue = this.getNestedValue(item, key);
2884
- if (Array.isArray(filterValue)) {
2885
- return filterValue.some((option) => {
2886
- const optionKey = option?.key || option;
2887
- return itemValue?.toString().toLowerCase() === optionKey?.toString().toLowerCase();
2888
- });
2889
- }
2890
- const v = filterValue?.key || filterValue;
2891
- return v ? itemValue?.toString().toLowerCase() === v.toString().toLowerCase() : true;
2892
- }));
2891
+ return this.originalData.filter((item) => {
2892
+ return Object.keys(this.currentFilters).every((key) => {
2893
+ const filterValue = this.currentFilters[key];
2894
+ if (!filterValue || (Array.isArray(filterValue) && filterValue.length === 0)) {
2895
+ return true;
2896
+ }
2897
+ const itemValue = this.getNestedValue(item, key);
2898
+ if (Array.isArray(filterValue)) {
2899
+ return filterValue.some((option) => {
2900
+ const optionKey = option?.key || option;
2901
+ return (itemValue?.toString().toLowerCase() === optionKey?.toString().toLowerCase());
2902
+ });
2903
+ }
2904
+ const singleFilterValue = filterValue?.key || filterValue;
2905
+ return singleFilterValue
2906
+ ? itemValue?.toString().toLowerCase() === singleFilterValue.toString().toLowerCase()
2907
+ : true;
2908
+ });
2909
+ });
2893
2910
  }
2894
2911
  applyFilters(filters) {
2895
2912
  const isEmpty = (v) => v === null ||
@@ -2939,8 +2956,11 @@ class TableComponent {
2939
2956
  this.loadLazyData({ first: 0, rows: 100 });
2940
2957
  }
2941
2958
  isRowSelectable(event) {
2942
- return typeof event.data?.canSelect === 'boolean' ? event.data.canSelect : true;
2959
+ return typeof event.data?.canSelect === 'boolean'
2960
+ ? event.data.canSelect
2961
+ : true;
2943
2962
  }
2963
+ // get nested value by dot path
2944
2964
  getNestedValue(obj, path) {
2945
2965
  try {
2946
2966
  if (obj && Object.prototype.hasOwnProperty.call(obj, path)) {
@@ -2963,6 +2983,7 @@ class TableComponent {
2963
2983
  }
2964
2984
  }
2965
2985
  applyColumns(selected) {
2986
+ // odloži promenu reference da izbegne NG0100
2966
2987
  const next = this.columns.filter((col) => selected.includes(col.field));
2967
2988
  Promise.resolve().then(() => {
2968
2989
  this.selectedColumns = next;
@@ -2974,19 +2995,19 @@ class TableComponent {
2974
2995
  this.rowSelection.emit(rowData);
2975
2996
  }
2976
2997
  onSelectionChange(selected) {
2977
- this.selectedItems.set(selected); // ⬅️ signal API
2998
+ this.selectedItems.set(selected);
2978
2999
  this.bulkMode = selected.length > 0;
2979
3000
  this.checkBoxSelection.emit(selected);
2980
3001
  }
2981
3002
  handleActionClick(event) {
2982
3003
  if (event?.action?.key === 'EXPORT_PDF') {
2983
- const baseName = this.tableConfiguration?.key ? `${this.tableConfiguration.key}.pdf` : 'table.pdf';
2984
- exportRowsToPdf(this.selectedColumns, this.tableData, this.columnTypeMap, this.columnTypeEnum, (k) => this.translateService.instant(k), baseName);
3004
+ const file = this.tableConfiguration?.key ? `${this.tableConfiguration.key}.pdf` : 'table.pdf';
3005
+ exportRowsToPdf(this.selectedColumns, this.tableData, this.columnTypeMap, this.columnTypeEnum, (k) => this.translateService.instant(k), file);
2985
3006
  return;
2986
3007
  }
2987
3008
  if (event?.action?.key === 'EXPORT_CSV') {
2988
- const baseName = this.tableConfiguration?.key ? `${this.tableConfiguration.key}.csv` : 'table.csv';
2989
- exportRowsToCsv(this.selectedColumns, this.tableData, this.columnTypeMap, this.columnTypeEnum, (k) => this.translateService.instant(k), baseName);
3009
+ const file = this.tableConfiguration?.key ? `${this.tableConfiguration.key}.csv` : 'table.csv';
3010
+ exportRowsToCsv(this.selectedColumns, this.tableData, this.columnTypeMap, this.columnTypeEnum, (k) => this.translateService.instant(k), file);
2990
3011
  return;
2991
3012
  }
2992
3013
  this.actionClick.emit(event);
@@ -3009,7 +3030,7 @@ class TableComponent {
3009
3030
  return false;
3010
3031
  }
3011
3032
  clearSelection() {
3012
- this.selectedItems.set([]); // ⬅️ signal API
3033
+ this.selectedItems.set([]);
3013
3034
  this.bulkMode = false;
3014
3035
  }
3015
3036
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });