@acorex/cdk 20.1.35 → 20.1.37

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,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { model, output, Component, inject, ElementRef, signal, afterNextRender, Injectable, ChangeDetectorRef, ViewContainerRef, EventEmitter, DOCUMENT, PLATFORM_ID, Renderer2, Input, Directive, NgModule, InjectionToken, Output, input, effect } from '@angular/core';
3
3
  import { AXHtmlUtil } from '@acorex/core/utils';
4
- import { flatten, clone, cloneDeep, isEqual, omit, set } from 'lodash-es';
4
+ import { flatten, clone, cloneDeep, isEqual, omit, set, get } from 'lodash-es';
5
5
  import { isBrowser } from '@acorex/core/platform';
6
6
  import { AXValidationService } from '@acorex/core/validation';
7
7
  import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
@@ -871,6 +871,12 @@ class AXButtonClickEvent extends AXClickEvent {
871
871
  */
872
872
  class AXItemClickEvent extends AXClickEvent {
873
873
  }
874
+ /**
875
+ * Fires each time the user select the element.
876
+ * @category Events
877
+ */
878
+ class AXItemSelectedEvent extends AXEvent {
879
+ }
874
880
  /**
875
881
  * Fires each time the component gets focused.
876
882
  * @category Events
@@ -1167,34 +1173,50 @@ class AXDataSource {
1167
1173
  }
1168
1174
  }
1169
1175
  function convertArrayToDataSource(items, options = { key: 'id', pageSize: 100 }) {
1176
+ // Normalize primitives to objects so consumers (e.g., select/list) can rely on
1177
+ // value and text fields without triggering extra byKey lookups.
1178
+ const normalizedItems = items.map((candidate) => {
1179
+ const isObjectItem = candidate != null && typeof candidate === 'object';
1180
+ if (isObjectItem) {
1181
+ return candidate;
1182
+ }
1183
+ // For primitive values, create an object with both key and text
1184
+ return { [options.key]: candidate, text: String(candidate ?? '') };
1185
+ });
1170
1186
  const config = {
1171
1187
  key: options.key,
1172
1188
  pageSize: options.pageSize,
1173
1189
  load: async (e) => {
1174
- const result = e.filter ? handleSearch(items, e.filter) : items;
1190
+ const itemsForFilter = normalizedItems;
1191
+ const resultNormalized = e.filter
1192
+ ? applyDataSourceQuery(itemsForFilter, e.filter)
1193
+ : itemsForFilter;
1194
+ const result = resultNormalized;
1175
1195
  return {
1176
1196
  items: result.slice(e.skip, e.skip + e.take),
1177
- total: result.length,
1197
+ total: resultNormalized.length,
1178
1198
  };
1179
1199
  },
1180
- byKey: (v) => Promise.resolve(items.find((c) => {
1181
- return c[options.key] == v;
1182
- })),
1183
- };
1184
- const handleSearch = (items, filter) => {
1185
- if (!filter?.field || filter.value === undefined || filter.value === null) {
1186
- return items; // No filter applied
1187
- }
1188
- return items.filter((item) => {
1189
- const itemField = item[filter.field];
1190
- if (typeof itemField === 'string' && typeof filter.value === 'string') {
1191
- return itemField.toLowerCase().includes(filter.value.toLowerCase());
1192
- }
1193
- return false; // Return false if itemField isn't comparable
1194
- });
1200
+ byKey: async (v) =>
1201
+ // Search in the normalized list (supports primitive and object arrays)
1202
+ normalizedItems.find((record) => {
1203
+ return record[options.key] == v;
1204
+ }),
1195
1205
  };
1196
1206
  return new AXDataSource(config);
1197
1207
  }
1208
+ function applyDataSourceQuery(items, filter) {
1209
+ if (!filter?.field || filter.value === undefined || filter.value === null) {
1210
+ return items; // No filter applied
1211
+ }
1212
+ return items.filter((item) => {
1213
+ const itemField = item[filter.field];
1214
+ if (typeof itemField === 'string' && typeof filter.value === 'string') {
1215
+ return itemField.toLowerCase().includes(filter.value.toLowerCase());
1216
+ }
1217
+ return false; // Return false if itemField isn't comparable
1218
+ });
1219
+ }
1198
1220
 
1199
1221
  const AX_STYLE_COLOR_TYPES = [
1200
1222
  'primary',
@@ -1722,8 +1744,18 @@ class MXSelectionValueComponent extends MXValueComponent {
1722
1744
  this._valueField = 'id';
1723
1745
  this._textField = 'text';
1724
1746
  this._textTemplate = '';
1747
+ this._defaultText = '-';
1725
1748
  this._disabledField = 'disabled';
1726
1749
  this._multiple = false;
1750
+ // #endregion
1751
+ // #region Events
1752
+ this.onItemSelected = new EventEmitter();
1753
+ /**
1754
+ * Emitted when an item in the list is clicked.
1755
+ *
1756
+ * @event
1757
+ */
1758
+ this.onItemClick = new EventEmitter();
1727
1759
  }
1728
1760
  /** Field name used to extract the unique value from items */
1729
1761
  get valueField() {
@@ -1746,6 +1778,13 @@ class MXSelectionValueComponent extends MXValueComponent {
1746
1778
  set textTemplate(value) {
1747
1779
  this.setOption({ name: 'textTemplate', value });
1748
1780
  }
1781
+ /** Text to display when neither textField nor valueField exist on the item */
1782
+ get defaultText() {
1783
+ return this._defaultText;
1784
+ }
1785
+ set defaultText(value) {
1786
+ this.setOption({ name: 'defaultText', value });
1787
+ }
1749
1788
  /** Field name used to determine if an item is disabled */
1750
1789
  get disabledField() {
1751
1790
  return this._disabledField;
@@ -1783,16 +1822,22 @@ class MXSelectionValueComponent extends MXValueComponent {
1783
1822
  if (value == null || (isArray && value.length === 0)) {
1784
1823
  return this.multiple ? [] : null;
1785
1824
  }
1786
- // Normalize items and find by key if needed
1825
+ // Check if items already have text properties to avoid unnecessary findByKey calls
1787
1826
  const itemsToNormalize = isArray ? value : [value];
1788
- const normalizedItems = this.normalizeItemsList(itemsToNormalize, true);
1827
+ const needsFindByKey = itemsToNormalize.some((item) => {
1828
+ if (typeof item === 'object' && item !== null) {
1829
+ return get(item, this.textField) == null;
1830
+ }
1831
+ return true; // Primitive values need findByKey
1832
+ });
1833
+ const normalizedItems = this.normalizeItemsList(itemsToNormalize, needsFindByKey);
1789
1834
  if (normalizedItems.length === 0) {
1790
1835
  return this.multiple ? [] : null;
1791
1836
  }
1792
1837
  // Extract values based on selection mode
1793
1838
  return this.multiple
1794
- ? normalizedItems.map(item => item[this.valueField])
1795
- : normalizedItems[0]?.[this.valueField] ?? null;
1839
+ ? normalizedItems.map((item) => get(item, this.valueField))
1840
+ : (get(normalizedItems[0], this.valueField) ?? null);
1796
1841
  }
1797
1842
  /**
1798
1843
  * Override to normalize selected items when value changes
@@ -1812,9 +1857,7 @@ class MXSelectionValueComponent extends MXValueComponent {
1812
1857
  normalizeItemsList(items, findByKey = false) {
1813
1858
  if (!items?.length)
1814
1859
  return [];
1815
- return items
1816
- .filter(item => item != null)
1817
- .map(item => this.normalizeItem(item, findByKey));
1860
+ return items.filter((item) => item != null).map((item) => this.normalizeItem(item, findByKey));
1818
1861
  }
1819
1862
  /**
1820
1863
  * Normalizes a single item, handling caching and async loading
@@ -1825,22 +1868,24 @@ class MXSelectionValueComponent extends MXValueComponent {
1825
1868
  normalizeItem(item, findByKey = false) {
1826
1869
  const isComplexObject = typeof item === 'object' && item !== null;
1827
1870
  const itemRecord = item;
1828
- const key = isComplexObject ? String(itemRecord[this.valueField]) : String(item);
1871
+ const valueKey = isComplexObject ? get(itemRecord, this.valueField) : item;
1872
+ const key = valueKey != null ? String(valueKey) : String(item);
1829
1873
  const cacheKey = this.createCacheKey(key);
1830
1874
  // Return cached item if available and has text
1831
1875
  const cachedItem = this.dataService.cacheList[cacheKey];
1832
- if (cachedItem && cachedItem[this.textField]) {
1876
+ if (cachedItem && get(cachedItem, this.textField) != null) {
1833
1877
  return cachedItem;
1834
1878
  }
1835
- const hasTextProperty = !isComplexObject || itemRecord[this.textField] != null;
1879
+ const hasTextProperty = !isComplexObject || get(itemRecord, this.textField) != null;
1836
1880
  const normalizedObj = {};
1837
- if (isComplexObject && hasTextProperty) {
1838
- // Item already has all required properties
1839
- Object.assign(normalizedObj, item);
1881
+ // If findByKey is true, we need to resolve the item to get its text
1882
+ // This is needed for string values like 'ir', 'us' that don't have text
1883
+ if (findByKey) {
1884
+ this.handleItemNormalization(normalizedObj, item, key, true, cacheKey);
1840
1885
  }
1841
1886
  else {
1842
- // Need to find or create item properties
1843
- this.handleItemNormalization(normalizedObj, item, key, findByKey, cacheKey);
1887
+ // Item already has all required properties, just copy them
1888
+ Object.assign(normalizedObj, item);
1844
1889
  }
1845
1890
  this.dataService.cacheList[cacheKey] = normalizedObj;
1846
1891
  return normalizedObj;
@@ -1867,9 +1912,9 @@ class MXSelectionValueComponent extends MXValueComponent {
1867
1912
  // Set loading state
1868
1913
  obj[this.valueField] = key;
1869
1914
  obj['isLoading'] = true;
1870
- obj[this.textField] = 'Loading';
1915
+ obj[this.textField] = '@acorex:common.status.loading';
1871
1916
  promise
1872
- .then(result => {
1917
+ .then((result) => {
1873
1918
  if (typeof result === 'object' && result) {
1874
1919
  Object.assign(obj, cloneDeep(result));
1875
1920
  }
@@ -1877,11 +1922,23 @@ class MXSelectionValueComponent extends MXValueComponent {
1877
1922
  obj[this.valueField] = result || key;
1878
1923
  obj[this.textField] = result;
1879
1924
  }
1925
+ })
1926
+ .catch((error) => {
1927
+ console.warn('Failed to load item by key:', key, error);
1928
+ // On error, keep the original value but mark as failed
1929
+ obj[this.textField] = this.defaultText;
1880
1930
  })
1881
1931
  .finally(() => {
1882
1932
  delete obj['isLoading'];
1933
+ delete obj['_displayTextLoading'];
1934
+ delete obj['_loadingTriggered'];
1883
1935
  this.dataService.cacheList[cacheKey] = obj;
1884
- this.cdr.markForCheck();
1936
+ // Use setTimeout to defer change detection and prevent immediate re-rendering
1937
+ setTimeout(() => {
1938
+ if (this.cdr) {
1939
+ this.cdr.markForCheck();
1940
+ }
1941
+ }, 0);
1885
1942
  });
1886
1943
  }
1887
1944
  /**
@@ -1891,12 +1948,16 @@ class MXSelectionValueComponent extends MXValueComponent {
1891
1948
  const isSourceObject = typeof sourceItem === 'object' && sourceItem !== null;
1892
1949
  const sourceRecord = sourceItem;
1893
1950
  if (isComplexSource && isSourceObject) {
1894
- obj[this.valueField] = sourceRecord[this.valueField];
1895
- obj[this.textField] = sourceRecord[this.textField];
1951
+ const valueFromSource = get(sourceRecord, this.valueField);
1952
+ const textFromSource = get(sourceRecord, this.textField);
1953
+ obj[this.valueField] = (valueFromSource ?? textFromSource);
1954
+ obj[this.textField] = (textFromSource ?? valueFromSource ?? this.defaultText);
1896
1955
  }
1897
1956
  else {
1898
- obj[this.valueField] = isSourceObject ? sourceRecord[this.valueField] : sourceItem;
1899
- obj[this.textField] = isSourceObject ? sourceRecord[this.textField] : sourceItem;
1957
+ const valueFromSource = isSourceObject ? get(sourceRecord, this.valueField) : sourceItem;
1958
+ const textFromSource = isSourceObject ? get(sourceRecord, this.textField) : sourceItem;
1959
+ obj[this.valueField] = (valueFromSource ?? textFromSource);
1960
+ obj[this.textField] = (textFromSource ?? valueFromSource ?? this.defaultText);
1900
1961
  }
1901
1962
  }
1902
1963
  /**
@@ -1909,10 +1970,13 @@ class MXSelectionValueComponent extends MXValueComponent {
1909
1970
  * Normalizes currently selected items and updates the data service
1910
1971
  */
1911
1972
  _normalizeSelectedItems() {
1912
- const values = Array.isArray(this.value)
1913
- ? this.value
1914
- : this.value != null ? [this.value] : [];
1915
- this.dataService.selectedItems = values.map(value => this.normalizeItem(value));
1973
+ const values = Array.isArray(this.value) ? this.value : this.value != null ? [this.value] : [];
1974
+ // Only call normalizeItem with findByKey=true if the item doesn't have text
1975
+ // This prevents unnecessary API calls for items that already have text
1976
+ this.dataService.selectedItems = values.map((value) => {
1977
+ const hasText = typeof value === 'object' && value !== null && get(value, this.textField) != null;
1978
+ return this.normalizeItem(value, !hasText);
1979
+ });
1916
1980
  }
1917
1981
  // #endregion
1918
1982
  // #region Public Selection Methods
@@ -1926,7 +1990,8 @@ class MXSelectionValueComponent extends MXValueComponent {
1926
1990
  return;
1927
1991
  }
1928
1992
  const normalizedItems = this.normalizeItemsList(items);
1929
- const newSelectedItems = this.selectedItems.filter(selectedItem => !normalizedItems.some(normalizedItem => normalizedItem[this.valueField] === selectedItem[this.valueField]));
1993
+ const newSelectedItems = this.selectedItems.filter((selectedItem) => !normalizedItems.some((normalizedItem) => get(normalizedItem, this.valueField) ===
1994
+ get(selectedItem, this.valueField)));
1930
1995
  this.commitValue(newSelectedItems, true);
1931
1996
  }
1932
1997
  /**
@@ -1934,13 +1999,18 @@ class MXSelectionValueComponent extends MXValueComponent {
1934
1999
  * @param items Items to select
1935
2000
  */
1936
2001
  selectItems(...items) {
1937
- if (!items?.length)
2002
+ if (!items?.length) {
1938
2003
  return;
2004
+ }
1939
2005
  const currentValue = Array.isArray(this.value) ? this.value : [this.value];
1940
2006
  const normalizedItems = this.normalizeItemsList(items);
1941
- const newSelectedItems = this.multiple
1942
- ? [...currentValue, ...normalizedItems]
1943
- : normalizedItems;
2007
+ const newSelectedItems = this.multiple ? [...currentValue, ...normalizedItems] : normalizedItems;
2008
+ this.onItemSelected.emit({
2009
+ component: this,
2010
+ isUserInteraction: true,
2011
+ item: newSelectedItems[0],
2012
+ htmlElement: this.getHostElement(),
2013
+ });
1944
2014
  this.commitValue(newSelectedItems, true);
1945
2015
  }
1946
2016
  /**
@@ -1948,11 +2018,9 @@ class MXSelectionValueComponent extends MXValueComponent {
1948
2018
  * @param items Items to toggle
1949
2019
  */
1950
2020
  toggleSelect(...items) {
1951
- items?.forEach(item => {
2021
+ items?.forEach((item) => {
1952
2022
  if (this.multiple) {
1953
- this.isItemSelected(item)
1954
- ? this.unselectItems(item)
1955
- : this.selectItems(item);
2023
+ this.isItemSelected(item) ? this.unselectItems(item) : this.selectItems(item);
1956
2024
  }
1957
2025
  else {
1958
2026
  this.selectItems(item);
@@ -1968,7 +2036,8 @@ class MXSelectionValueComponent extends MXValueComponent {
1968
2036
  */
1969
2037
  isItemSelected(item) {
1970
2038
  const normalizedItem = this.normalizeItem(item);
1971
- return this.selectedItems.some(selectedItem => selectedItem[this.valueField] === normalizedItem[this.valueField]);
2039
+ const normalizedValue = get(normalizedItem, this.valueField);
2040
+ return this.selectedItems.some((selectedItem) => get(selectedItem, this.valueField) === normalizedValue);
1972
2041
  }
1973
2042
  /**
1974
2043
  * Checks if an item is disabled
@@ -1978,9 +2047,18 @@ class MXSelectionValueComponent extends MXValueComponent {
1978
2047
  isItemDisabled(item) {
1979
2048
  const itemRecord = item;
1980
2049
  return (this.disabled ||
1981
- coerceBooleanProperty(itemRecord[this.disabledField]) === true ||
2050
+ coerceBooleanProperty(get(itemRecord, this.disabledField)) === true ||
1982
2051
  (this.disabledCallback?.({ item, index: -1 }) ?? false));
1983
2052
  }
2053
+ /**
2054
+ * Checks if an item is currently loading
2055
+ * @param item Item to check
2056
+ * @returns True if the item is loading
2057
+ */
2058
+ isItemLoading(item) {
2059
+ const normalizedItem = this.normalizeItem(item);
2060
+ return normalizedItem['isLoading'] === true;
2061
+ }
1984
2062
  // #endregion
1985
2063
  // #region Protected Utility Methods
1986
2064
  /**
@@ -1989,22 +2067,109 @@ class MXSelectionValueComponent extends MXValueComponent {
1989
2067
  * @returns Formatted display text
1990
2068
  */
1991
2069
  getDisplayText(item) {
1992
- const normalizedItem = this.normalizeItem(item);
2070
+ // Prevent recursive calls that could cause infinite loops
2071
+ if (item && typeof item === 'object' && item['_displayTextLoading']) {
2072
+ return '@acorex:common.status.loading';
2073
+ }
2074
+ // Add timestamp-based debouncing to prevent excessive calls for ALL item types
2075
+ const now = Date.now();
2076
+ const itemKey = typeof item === 'string' ? item : get(item, this.valueField);
2077
+ const cacheKey = this.createCacheKey(String(itemKey));
2078
+ // Check if we have a recent result in the cache to prevent duplicate processing
2079
+ const cachedResult = this.dataService.cacheList[cacheKey];
2080
+ if (cachedResult && cachedResult['_lastDisplayTextCall']) {
2081
+ const timeSinceLastCall = now - cachedResult['_lastDisplayTextCall'];
2082
+ if (timeSinceLastCall < 50) {
2083
+ // 50ms debounce
2084
+ return cachedResult['_lastDisplayTextResult'] || String(itemKey || '');
2085
+ }
2086
+ }
2087
+ // For string values, we need to normalize with findByKey=true to trigger async loading
2088
+ const isStringValue = typeof item === 'string';
2089
+ const normalizedItem = this.normalizeItem(item, isStringValue);
2090
+ // Check if this item is already in the cache with proper text
2091
+ const itemValue = get(normalizedItem, this.valueField);
2092
+ if (itemValue != null && itemValue !== '') {
2093
+ const cacheKey = this.createCacheKey(String(itemValue));
2094
+ const cachedItem = this.dataService.cacheList[cacheKey];
2095
+ if (cachedItem && get(cachedItem, this.textField) != null) {
2096
+ // Use cached text if available
2097
+ const cachedText = get(cachedItem, this.textField);
2098
+ if (cachedText && cachedText !== '@acorex:common.status.loading') {
2099
+ const result = String(cachedText);
2100
+ // Cache the timestamp and result for debouncing in the cache (works for all item types)
2101
+ if (cachedItem) {
2102
+ cachedItem['_lastDisplayTextCall'] = now;
2103
+ cachedItem['_lastDisplayTextResult'] = result;
2104
+ }
2105
+ return result;
2106
+ }
2107
+ }
2108
+ }
1993
2109
  // Try template formatting first
1994
2110
  if (this.textTemplate) {
1995
2111
  const formattedTemplate = this.formatService.format(this.textTemplate, 'string', normalizedItem);
1996
2112
  if (formattedTemplate !== this.textTemplate) {
1997
- return formattedTemplate;
2113
+ const result = formattedTemplate;
2114
+ // Cache the timestamp and result for debouncing in the cache
2115
+ if (normalizedItem) {
2116
+ normalizedItem['_lastDisplayTextCall'] = now;
2117
+ normalizedItem['_lastDisplayTextResult'] = result;
2118
+ }
2119
+ return result;
1998
2120
  }
1999
2121
  }
2000
2122
  // Use text field or fallback to value field
2001
- if (normalizedItem[this.textField]) {
2002
- return String(normalizedItem[this.textField]);
2123
+ const textValue = get(normalizedItem, this.textField);
2124
+ if (textValue != null && textValue !== '') {
2125
+ const result = String(textValue);
2126
+ // Cache the timestamp and result for debouncing in the cache
2127
+ if (normalizedItem) {
2128
+ normalizedItem['_lastDisplayTextCall'] = now;
2129
+ normalizedItem['_lastDisplayTextResult'] = result;
2130
+ }
2131
+ return result;
2132
+ }
2133
+ // If text is missing and item is loading, show loading state
2134
+ if (normalizedItem['isLoading']) {
2135
+ const result = '@acorex:common.status.loading';
2136
+ // Cache the timestamp and result for debouncing in the cache
2137
+ if (normalizedItem) {
2138
+ normalizedItem['_lastDisplayTextCall'] = now;
2139
+ normalizedItem['_lastDisplayTextResult'] = result;
2140
+ }
2141
+ return result;
2003
2142
  }
2004
2143
  // Attempt to load item by key if text is missing
2005
- const value = normalizedItem[this.valueField];
2006
- this.loadAndCacheItemByKey(value);
2007
- return String(value);
2144
+ const value = get(normalizedItem, this.valueField);
2145
+ if (value == null || value === '') {
2146
+ const result = this.defaultText;
2147
+ // Cache the timestamp and result for debouncing in the cache
2148
+ if (normalizedItem) {
2149
+ normalizedItem['_lastDisplayTextCall'] = now;
2150
+ normalizedItem['_lastDisplayTextResult'] = result;
2151
+ }
2152
+ return result;
2153
+ }
2154
+ // If we have a value but no text, trigger async loading only once
2155
+ // Use a flag to prevent multiple calls
2156
+ if (!normalizedItem['_loadingTriggered'] && !normalizedItem[this.textField]) {
2157
+ normalizedItem['_loadingTriggered'] = true;
2158
+ normalizedItem['_displayTextLoading'] = true;
2159
+ // Use setTimeout to defer the async loading and prevent immediate change detection
2160
+ setTimeout(() => {
2161
+ this.loadAndCacheItemByKey(value);
2162
+ }, 0);
2163
+ }
2164
+ // Return the value itself as a fallback
2165
+ // This will be updated once the async loading completes
2166
+ const result = String(value);
2167
+ // Cache the timestamp and result for debouncing in the cache
2168
+ if (normalizedItem) {
2169
+ normalizedItem['_lastDisplayTextCall'] = now;
2170
+ normalizedItem['_lastDisplayTextResult'] = result;
2171
+ }
2172
+ return result;
2008
2173
  }
2009
2174
  /**
2010
2175
  * Gets the value of an item
@@ -2013,7 +2178,7 @@ class MXSelectionValueComponent extends MXValueComponent {
2013
2178
  */
2014
2179
  getValue(item) {
2015
2180
  const normalizedItem = this.normalizeItem(item);
2016
- return normalizedItem[this.valueField];
2181
+ return get(normalizedItem, this.valueField);
2017
2182
  }
2018
2183
  /**
2019
2184
  * Clears the selection cache and selected items
@@ -2030,6 +2195,52 @@ class MXSelectionValueComponent extends MXValueComponent {
2030
2195
  this.dataService.cacheList = {};
2031
2196
  this.cdr.markForCheck();
2032
2197
  }
2198
+ /**
2199
+ * Clears the debouncing cache for specific items to ensure fresh data is displayed
2200
+ */
2201
+ clearItemDebouncingCache(item) {
2202
+ // Get the cache key for this item
2203
+ const itemKey = typeof item === 'string' ? item : get(item, this.valueField);
2204
+ if (itemKey != null) {
2205
+ const cacheKey = this.createCacheKey(String(itemKey));
2206
+ const cachedItem = this.dataService.cacheList[cacheKey];
2207
+ if (cachedItem) {
2208
+ delete cachedItem['_lastDisplayTextCall'];
2209
+ delete cachedItem['_lastDisplayTextResult'];
2210
+ delete cachedItem['_displayTextLoading'];
2211
+ delete cachedItem['_loadingTriggered'];
2212
+ }
2213
+ }
2214
+ }
2215
+ /**
2216
+ * Forces a refresh of the display when items are loaded asynchronously
2217
+ * This should be called when the data source is updated
2218
+ */
2219
+ refreshDisplay() {
2220
+ this.cdr.markForCheck();
2221
+ }
2222
+ /**
2223
+ * Refreshes the display for all selected items to ensure consistency
2224
+ * This is useful when the data source has been updated
2225
+ */
2226
+ refreshSelectedItemsDisplay() {
2227
+ // Force a refresh of the display without re-normalizing to avoid infinite loops
2228
+ if (this.selectedItems.length > 0) {
2229
+ this.cdr.markForCheck();
2230
+ }
2231
+ }
2232
+ /**
2233
+ * Forces a refresh of all selected items by clearing their debouncing cache
2234
+ * This ensures fresh data is displayed when the data source is updated
2235
+ */
2236
+ forceRefreshSelectedItems() {
2237
+ if (this.selectedItems.length > 0) {
2238
+ this.selectedItems.forEach((item) => {
2239
+ this.clearItemDebouncingCache(item);
2240
+ });
2241
+ this.cdr.markForCheck();
2242
+ }
2243
+ }
2033
2244
  // #endregion
2034
2245
  // #region Private Helper Methods
2035
2246
  /**
@@ -2042,12 +2253,29 @@ class MXSelectionValueComponent extends MXValueComponent {
2042
2253
  if (item) {
2043
2254
  const normalizedItem = this.normalizeItem(item);
2044
2255
  const cacheKey = this.createCacheKey(String(normalizedItem[this.valueField]));
2256
+ // Update the cache with the loaded item
2045
2257
  this.dataService.cacheList[cacheKey] = normalizedItem;
2046
- this.cdr.markForCheck();
2258
+ // Clear loading flags
2259
+ if (this.dataService.cacheList[cacheKey]) {
2260
+ delete this.dataService.cacheList[cacheKey]['_displayTextLoading'];
2261
+ delete this.dataService.cacheList[cacheKey]['_loadingTriggered'];
2262
+ }
2263
+ // Use setTimeout to defer change detection and prevent immediate re-rendering
2264
+ setTimeout(() => {
2265
+ if (this.cdr) {
2266
+ this.cdr.markForCheck();
2267
+ }
2268
+ }, 0);
2047
2269
  }
2048
2270
  }
2049
2271
  catch (error) {
2050
2272
  console.warn('Failed to load item by key:', key, error);
2273
+ // Clear loading flags on error too
2274
+ const cacheKey = this.createCacheKey(String(key));
2275
+ if (this.dataService.cacheList[cacheKey]) {
2276
+ delete this.dataService.cacheList[cacheKey]['_displayTextLoading'];
2277
+ delete this.dataService.cacheList[cacheKey]['_loadingTriggered'];
2278
+ }
2051
2279
  }
2052
2280
  }
2053
2281
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.4", ngImport: i0, type: MXSelectionValueComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
@@ -2215,5 +2443,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.4", ngImpor
2215
2443
  * Generated bundle index. Do not edit.
2216
2444
  */
2217
2445
 
2218
- export { AXAutoFocusDirective, AXAutocompleteParentComponent, AXButtonClickEvent, AXClearableComponent, AXClickEvent, AXClosableComponent, AXCommonModule, AXComponent, AXComponentCloseEvent, AXComponentClosedPromise, AXComponentClosing, AXComponentResult, AXDataSource, AXDomService, AXEvent, AXFocusEvent, AXFocusableComponent, AXHotkeyDirective, AXHotkeysService, AXHtmlEvent, AXInfiniteScrollerDirective, AXInvertedColorDirective, AXItemClickEvent, AXListDataSource, AXNgModelDelayedValueChangedDirective, AXOptionChangedEvent, AXPagedComponent, AXRangeChangedEvent, AXResponsiveDirective, AXRippleDirective, AXSearchableComponent, AXSelectionValueChangedEvent, AXValuableComponent, AXValueChangedEvent, AX_LOCATIONS, AX_PLACEMENT_BOTTOM, AX_PLACEMENT_BOTTOM_END, AX_PLACEMENT_BOTTOM_START, AX_PLACEMENT_END, AX_PLACEMENT_END_BOTTOM, AX_PLACEMENT_END_TOP, AX_PLACEMENT_MAP, AX_PLACEMENT_START, AX_PLACEMENT_START_BOTTOM, AX_PLACEMENT_START_TOP, AX_PLACEMENT_TOP, AX_PLACEMENT_TOP_END, AX_PLACEMENT_TOP_START, AX_SELECTION_DATA_TOKEN, AX_STYLE_COLOR_TYPES, AX_STYLE_LOOK_TYPES, MXBaseComponent, MXButtonBaseComponent, MXColorComponent, MXColorLookComponent, MXInputBaseValueComponent, MXInteractiveComponent, MXLookComponent, MXLookableComponent, MXSelectionBridgeService, MXSelectionValueComponent, MXValueComponent, NXButtonComponent, NXClickEvent, NXColorComponent, NXComponent, NXEvent, NXInteractiveComponent, NXLookComponent, NXNativeEvent, NXValueComponent, TAB_META_KEY, convertArrayToDataSource, convertToPlacement };
2446
+ export { AXAutoFocusDirective, AXAutocompleteParentComponent, AXButtonClickEvent, AXClearableComponent, AXClickEvent, AXClosableComponent, AXCommonModule, AXComponent, AXComponentCloseEvent, AXComponentClosedPromise, AXComponentClosing, AXComponentResult, AXDataSource, AXDomService, AXEvent, AXFocusEvent, AXFocusableComponent, AXHotkeyDirective, AXHotkeysService, AXHtmlEvent, AXInfiniteScrollerDirective, AXInvertedColorDirective, AXItemClickEvent, AXItemSelectedEvent, AXListDataSource, AXNgModelDelayedValueChangedDirective, AXOptionChangedEvent, AXPagedComponent, AXRangeChangedEvent, AXResponsiveDirective, AXRippleDirective, AXSearchableComponent, AXSelectionValueChangedEvent, AXValuableComponent, AXValueChangedEvent, AX_LOCATIONS, AX_PLACEMENT_BOTTOM, AX_PLACEMENT_BOTTOM_END, AX_PLACEMENT_BOTTOM_START, AX_PLACEMENT_END, AX_PLACEMENT_END_BOTTOM, AX_PLACEMENT_END_TOP, AX_PLACEMENT_MAP, AX_PLACEMENT_START, AX_PLACEMENT_START_BOTTOM, AX_PLACEMENT_START_TOP, AX_PLACEMENT_TOP, AX_PLACEMENT_TOP_END, AX_PLACEMENT_TOP_START, AX_SELECTION_DATA_TOKEN, AX_STYLE_COLOR_TYPES, AX_STYLE_LOOK_TYPES, MXBaseComponent, MXButtonBaseComponent, MXColorComponent, MXColorLookComponent, MXInputBaseValueComponent, MXInteractiveComponent, MXLookComponent, MXLookableComponent, MXSelectionBridgeService, MXSelectionValueComponent, MXValueComponent, NXButtonComponent, NXClickEvent, NXColorComponent, NXComponent, NXEvent, NXInteractiveComponent, NXLookComponent, NXNativeEvent, NXValueComponent, TAB_META_KEY, applyDataSourceQuery, convertArrayToDataSource, convertToPlacement };
2219
2447
  //# sourceMappingURL=acorex-cdk-common.mjs.map