@acorex/cdk 20.1.20 → 20.1.21

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.
@@ -1621,9 +1621,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImpor
1621
1621
  type: Injectable
1622
1622
  }] });
1623
1623
 
1624
+ /**
1625
+ * Service that manages selection state and caching for selection components
1626
+ */
1624
1627
  class MXSelectionBridgeService {
1625
1628
  constructor() {
1629
+ /** Array of currently selected items */
1626
1630
  this.selectedItems = [];
1631
+ /** Cache for normalized items keyed by their unique identifier */
1627
1632
  this.cacheList = {};
1628
1633
  }
1629
1634
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: MXSelectionBridgeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
@@ -1632,209 +1637,352 @@ class MXSelectionBridgeService {
1632
1637
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: MXSelectionBridgeService, decorators: [{
1633
1638
  type: Injectable
1634
1639
  }] });
1640
+ /**
1641
+ * Injection token for the selection bridge service
1642
+ */
1635
1643
  const AX_SELECTION_DATA_TOKEN = new InjectionToken('AX_SELECTION_DATA_TOKEN');
1644
+ /**
1645
+ * Abstract base component for selection-based value components
1646
+ * Provides common functionality for components that support item selection
1647
+ */
1636
1648
  class MXSelectionValueComponent extends MXValueComponent {
1637
1649
  constructor() {
1638
1650
  super(...arguments);
1651
+ // #region Services
1639
1652
  this.formatService = inject(AXFormatService);
1640
1653
  this.dataService = inject(AX_SELECTION_DATA_TOKEN);
1654
+ // #region Field Configuration Properties
1641
1655
  this._valueField = 'id';
1642
- this._textTemplate = '';
1643
1656
  this._textField = 'text';
1657
+ this._textTemplate = '';
1644
1658
  this._disabledField = 'disabled';
1645
1659
  this._multiple = false;
1646
1660
  }
1661
+ /** Field name used to extract the unique value from items */
1647
1662
  get valueField() {
1648
1663
  return this._valueField;
1649
1664
  }
1650
- set valueField(v) {
1651
- this.setOption({
1652
- name: 'valueField',
1653
- value: v,
1654
- });
1655
- }
1656
- get textTemplate() {
1657
- return this._textTemplate;
1658
- }
1659
- set textTemplate(v) {
1660
- this.setOption({
1661
- name: 'textTemplate',
1662
- value: v,
1663
- });
1665
+ set valueField(value) {
1666
+ this.setOption({ name: 'valueField', value });
1664
1667
  }
1668
+ /** Field name used to extract the display text from items */
1665
1669
  get textField() {
1666
1670
  return this._textField;
1667
1671
  }
1668
- set textField(v) {
1669
- this.setOption({
1670
- name: 'textField',
1671
- value: v,
1672
- });
1672
+ set textField(value) {
1673
+ this.setOption({ name: 'textField', value });
1673
1674
  }
1675
+ /** Template string for formatting item display text */
1676
+ get textTemplate() {
1677
+ return this._textTemplate;
1678
+ }
1679
+ set textTemplate(value) {
1680
+ this.setOption({ name: 'textTemplate', value });
1681
+ }
1682
+ /** Field name used to determine if an item is disabled */
1674
1683
  get disabledField() {
1675
1684
  return this._disabledField;
1676
1685
  }
1677
- set disabledField(v) {
1678
- this.setOption({
1679
- name: 'disabledField',
1680
- value: v,
1681
- });
1686
+ set disabledField(value) {
1687
+ this.setOption({ name: 'disabledField', value });
1682
1688
  }
1689
+ /** Whether multiple items can be selected */
1683
1690
  get multiple() {
1684
1691
  return this._multiple;
1685
1692
  }
1686
- set multiple(v) {
1693
+ set multiple(value) {
1687
1694
  this.setOption({
1688
1695
  name: 'multiple',
1689
- value: v,
1690
- afterCallback: () => {
1691
- this.reset(false);
1692
- },
1696
+ value,
1697
+ afterCallback: () => this.reset(false),
1693
1698
  });
1694
1699
  }
1700
+ // #endregion
1701
+ // #region Computed Properties
1702
+ /** Gets the currently selected items */
1695
1703
  get selectedItems() {
1696
1704
  return this.dataService.selectedItems || [];
1697
1705
  }
1706
+ // #endregion
1707
+ // #region Override Methods
1708
+ /**
1709
+ * Internal method to set and normalize the component value
1710
+ * @param value The value to set (can be single item or array)
1711
+ * @returns Normalized value based on multiple selection mode
1712
+ */
1698
1713
  internalSetValue(value) {
1699
1714
  const isArray = Array.isArray(value);
1700
- if (value == null || (isArray && value.length == 0)) {
1715
+ // Handle null/empty values
1716
+ if (value == null || (isArray && value.length === 0)) {
1701
1717
  return this.multiple ? [] : null;
1702
1718
  }
1703
- const normalizedItems = isArray ? this.normalizeItemsList(value, true) : this.normalizeItemsList([value], true);
1704
- if (normalizedItems.length == 0) {
1719
+ // Normalize items and find by key if needed
1720
+ const itemsToNormalize = isArray ? value : [value];
1721
+ const normalizedItems = this.normalizeItemsList(itemsToNormalize, true);
1722
+ if (normalizedItems.length === 0) {
1705
1723
  return this.multiple ? [] : null;
1706
1724
  }
1707
- const result = this.multiple ? normalizedItems.map((c) => c[this.valueField]) : normalizedItems[0][this.valueField];
1708
- return result;
1725
+ // Extract values based on selection mode
1726
+ return this.multiple
1727
+ ? normalizedItems.map(item => item[this.valueField])
1728
+ : normalizedItems[0]?.[this.valueField] ?? null;
1709
1729
  }
1730
+ /**
1731
+ * Override to normalize selected items when value changes
1732
+ */
1710
1733
  emitOnValueChangedEvent(oldValue, newValue) {
1711
1734
  this._normalizeSelectedItems();
1712
1735
  super.emitOnValueChangedEvent(oldValue, newValue);
1713
1736
  }
1714
- normalizeItemsList(items, findBykey = false) {
1715
- if (items == null)
1737
+ // #endregion
1738
+ // #region Private Normalization Methods
1739
+ /**
1740
+ * Normalizes a list of items, filtering out null values
1741
+ * @param items Array of items to normalize
1742
+ * @param findByKey Whether to attempt finding items by key
1743
+ * @returns Array of normalized items
1744
+ */
1745
+ normalizeItemsList(items, findByKey = false) {
1746
+ if (!items?.length)
1716
1747
  return [];
1717
- return items.filter((c) => c != null).map((i) => this.normalizeItem(i, findBykey));
1748
+ return items
1749
+ .filter(item => item != null)
1750
+ .map(item => this.normalizeItem(item, findByKey));
1718
1751
  }
1719
- normalizeItem(item, findBykey = false) {
1720
- const complex = typeof item == 'object';
1721
- const key = complex ? item[this.valueField] : `${item}`;
1722
- const cacheKey = `k-${key}`;
1723
- const hasText = !complex || item[this.textField] != null;
1724
- //
1725
- if (this.dataService.cacheList[cacheKey] && this.dataService.cacheList[cacheKey][this.textField])
1726
- return this.dataService.cacheList[cacheKey];
1727
- //
1728
- const obj = {};
1729
- if (complex && hasText) {
1730
- Object.assign(obj, item);
1752
+ /**
1753
+ * Normalizes a single item, handling caching and async loading
1754
+ * @param item Item to normalize
1755
+ * @param findByKey Whether to attempt finding the item by key
1756
+ * @returns Normalized item object
1757
+ */
1758
+ normalizeItem(item, findByKey = false) {
1759
+ const isComplexObject = typeof item === 'object' && item !== null;
1760
+ const itemRecord = item;
1761
+ const key = isComplexObject ? String(itemRecord[this.valueField]) : String(item);
1762
+ const cacheKey = this.createCacheKey(key);
1763
+ // Return cached item if available and has text
1764
+ const cachedItem = this.dataService.cacheList[cacheKey];
1765
+ if (cachedItem && cachedItem[this.textField]) {
1766
+ return cachedItem;
1767
+ }
1768
+ const hasTextProperty = !isComplexObject || itemRecord[this.textField] != null;
1769
+ const normalizedObj = {};
1770
+ if (isComplexObject && hasTextProperty) {
1771
+ // Item already has all required properties
1772
+ Object.assign(normalizedObj, item);
1731
1773
  }
1732
1774
  else {
1733
- const existsItem = findBykey ? this.getItemByKey(key) : null;
1734
- if (existsItem && existsItem instanceof Promise) {
1735
- obj[this.valueField] = key;
1736
- obj['isLoading'] = true;
1737
- obj[this.textField] = 'Loading';
1738
- //
1739
- existsItem
1740
- .then((r) => {
1741
- if (typeof r === 'object' && r) {
1742
- // obj[this.valueField] = r[this.valueField];
1743
- // obj[this.textField] = r[this.textField];
1744
- Object.assign(obj, cloneDeep(r));
1745
- }
1746
- else {
1747
- obj[this.valueField] = r || key;
1748
- obj[this.textField] = r;
1749
- }
1750
- })
1751
- .finally(() => {
1752
- delete obj['isLoading'];
1753
- this.dataService.cacheList[cacheKey] = obj;
1754
- this.cdr.markForCheck();
1755
- });
1756
- }
1757
- else if (existsItem) {
1758
- obj[this.valueField] = complex ? existsItem[this.valueField] : existsItem;
1759
- obj[this.textField] = complex ? existsItem[this.textField] : existsItem;
1775
+ // Need to find or create item properties
1776
+ this.handleItemNormalization(normalizedObj, item, key, findByKey, cacheKey);
1777
+ }
1778
+ this.dataService.cacheList[cacheKey] = normalizedObj;
1779
+ return normalizedObj;
1780
+ }
1781
+ /**
1782
+ * Handles the normalization logic for items that need property assignment
1783
+ */
1784
+ handleItemNormalization(normalizedObj, originalItem, key, findByKey, cacheKey) {
1785
+ const existingItem = findByKey ? this.getItemByKey(key) : null;
1786
+ if (existingItem instanceof Promise) {
1787
+ this.handleAsyncItem(normalizedObj, key, existingItem, cacheKey);
1788
+ }
1789
+ else if (existingItem) {
1790
+ this.assignItemProperties(normalizedObj, existingItem, true);
1791
+ }
1792
+ else {
1793
+ this.assignItemProperties(normalizedObj, originalItem, false);
1794
+ }
1795
+ }
1796
+ /**
1797
+ * Handles async item loading with loading state
1798
+ */
1799
+ handleAsyncItem(obj, key, promise, cacheKey) {
1800
+ // Set loading state
1801
+ obj[this.valueField] = key;
1802
+ obj['isLoading'] = true;
1803
+ obj[this.textField] = 'Loading';
1804
+ promise
1805
+ .then(result => {
1806
+ if (typeof result === 'object' && result) {
1807
+ Object.assign(obj, cloneDeep(result));
1760
1808
  }
1761
1809
  else {
1762
- obj[this.valueField] = complex ? item[this.valueField] : item;
1763
- obj[this.textField] = complex ? item[this.textField] : item;
1810
+ obj[this.valueField] = result || key;
1811
+ obj[this.textField] = result;
1764
1812
  }
1813
+ })
1814
+ .finally(() => {
1815
+ delete obj['isLoading'];
1816
+ this.dataService.cacheList[cacheKey] = obj;
1817
+ this.cdr.markForCheck();
1818
+ });
1819
+ }
1820
+ /**
1821
+ * Assigns value and text properties to the normalized object
1822
+ */
1823
+ assignItemProperties(obj, sourceItem, isComplexSource) {
1824
+ const isSourceObject = typeof sourceItem === 'object' && sourceItem !== null;
1825
+ const sourceRecord = sourceItem;
1826
+ if (isComplexSource && isSourceObject) {
1827
+ obj[this.valueField] = sourceRecord[this.valueField];
1828
+ obj[this.textField] = sourceRecord[this.textField];
1765
1829
  }
1766
- this.dataService.cacheList[cacheKey] = obj;
1767
- return obj;
1830
+ else {
1831
+ obj[this.valueField] = isSourceObject ? sourceRecord[this.valueField] : sourceItem;
1832
+ obj[this.textField] = isSourceObject ? sourceRecord[this.textField] : sourceItem;
1833
+ }
1834
+ }
1835
+ /**
1836
+ * Creates a consistent cache key for an item
1837
+ */
1838
+ createCacheKey(key) {
1839
+ return `k-${key}`;
1768
1840
  }
1841
+ /**
1842
+ * Normalizes currently selected items and updates the data service
1843
+ */
1769
1844
  _normalizeSelectedItems() {
1770
- const values = Array.isArray(this.value) ? this.value : this.value != null ? [this.value] : [];
1771
- this.dataService.selectedItems = values.map((v) => this.normalizeItem(v));
1845
+ const values = Array.isArray(this.value)
1846
+ ? this.value
1847
+ : this.value != null ? [this.value] : [];
1848
+ this.dataService.selectedItems = values.map(value => this.normalizeItem(value));
1772
1849
  }
1850
+ // #endregion
1851
+ // #region Public Selection Methods
1852
+ /**
1853
+ * Unselects the specified items from the selection
1854
+ * @param items Items to unselect
1855
+ */
1773
1856
  unselectItems(...items) {
1774
- if (!items || items.length === 0) {
1857
+ if (!items?.length) {
1775
1858
  this.commitValue([], true);
1776
1859
  return;
1777
1860
  }
1778
- const normalizeItems = Array.isArray(items) ? this.normalizeItemsList(items) : [this.normalizeItem(items)];
1779
- const newSelectedItems = this.selectedItems.filter((i) => !normalizeItems.some((n) => n[this.valueField] == i[this.valueField]));
1861
+ const normalizedItems = this.normalizeItemsList(items);
1862
+ const newSelectedItems = this.selectedItems.filter(selectedItem => !normalizedItems.some(normalizedItem => normalizedItem[this.valueField] === selectedItem[this.valueField]));
1780
1863
  this.commitValue(newSelectedItems, true);
1781
1864
  }
1865
+ /**
1866
+ * Selects the specified items
1867
+ * @param items Items to select
1868
+ */
1782
1869
  selectItems(...items) {
1783
- if (items && items.length) {
1784
- let newSelectedItems = Array.isArray(this.value) ? this.value : [this.value];
1785
- const normalizeItems = Array.isArray(items) ? this.normalizeItemsList(items) : [this.normalizeItem(items)];
1786
- if (this.multiple) {
1787
- newSelectedItems = [...newSelectedItems, ...normalizeItems];
1788
- }
1789
- else {
1790
- newSelectedItems = normalizeItems;
1791
- }
1792
- this.commitValue(newSelectedItems, true);
1793
- }
1870
+ if (!items?.length)
1871
+ return;
1872
+ const currentValue = Array.isArray(this.value) ? this.value : [this.value];
1873
+ const normalizedItems = this.normalizeItemsList(items);
1874
+ const newSelectedItems = this.multiple
1875
+ ? [...currentValue, ...normalizedItems]
1876
+ : normalizedItems;
1877
+ this.commitValue(newSelectedItems, true);
1794
1878
  }
1879
+ /**
1880
+ * Toggles the selection state of the specified items
1881
+ * @param items Items to toggle
1882
+ */
1795
1883
  toggleSelect(...items) {
1796
- items?.forEach((item) => {
1884
+ items?.forEach(item => {
1797
1885
  if (this.multiple) {
1798
- this.isItemSelected(item) ? this.unselectItems(item) : this.selectItems(item);
1886
+ this.isItemSelected(item)
1887
+ ? this.unselectItems(item)
1888
+ : this.selectItems(item);
1799
1889
  }
1800
1890
  else {
1801
1891
  this.selectItems(item);
1802
1892
  }
1803
1893
  });
1804
1894
  }
1895
+ // #endregion
1896
+ // #region Public Utility Methods
1897
+ /**
1898
+ * Checks if an item is currently selected
1899
+ * @param item Item to check
1900
+ * @returns True if the item is selected
1901
+ */
1805
1902
  isItemSelected(item) {
1806
- return this.selectedItems.some((c) => c[this.valueField] === this.normalizeItem(item)[this.valueField]);
1903
+ const normalizedItem = this.normalizeItem(item);
1904
+ return this.selectedItems.some(selectedItem => selectedItem[this.valueField] === normalizedItem[this.valueField]);
1807
1905
  }
1906
+ /**
1907
+ * Checks if an item is disabled
1908
+ * @param item Item to check
1909
+ * @returns True if the item is disabled
1910
+ */
1808
1911
  isItemDisabled(item) {
1912
+ const itemRecord = item;
1809
1913
  return (this.disabled ||
1810
- coerceBooleanProperty(item[this.disabledField]) === true ||
1811
- (this.disabledCallback ? this.disabledCallback({ item, index: -1 }) : false));
1914
+ coerceBooleanProperty(itemRecord[this.disabledField]) === true ||
1915
+ (this.disabledCallback?.({ item, index: -1 }) ?? false));
1812
1916
  }
1813
- // protected getDisplayText(item: T) {
1814
- // const normalizeItem = this.normalizeItem(item) as any;
1815
- // return formattedText || normalizeItem[this.valueField];
1816
- // }
1917
+ // #endregion
1918
+ // #region Protected Utility Methods
1919
+ /**
1920
+ * Gets the display text for an item using template or text field
1921
+ * @param item Item to get display text for
1922
+ * @returns Formatted display text
1923
+ */
1817
1924
  getDisplayText(item) {
1818
- const normalizeItem = this.normalizeItem(item);
1819
- const formattedTemplate = this.formatService.format(this.textTemplate, 'string', normalizeItem);
1820
- if (this.textTemplate && formattedTemplate != this.textTemplate)
1821
- return formattedTemplate;
1822
- else
1823
- return normalizeItem[this.textField] || normalizeItem[this.valueField];
1925
+ const normalizedItem = this.normalizeItem(item);
1926
+ // Try template formatting first
1927
+ if (this.textTemplate) {
1928
+ const formattedTemplate = this.formatService.format(this.textTemplate, 'string', normalizedItem);
1929
+ if (formattedTemplate !== this.textTemplate) {
1930
+ return formattedTemplate;
1931
+ }
1932
+ }
1933
+ // Use text field or fallback to value field
1934
+ if (normalizedItem[this.textField]) {
1935
+ return String(normalizedItem[this.textField]);
1936
+ }
1937
+ // Attempt to load item by key if text is missing
1938
+ const value = normalizedItem[this.valueField];
1939
+ this.loadAndCacheItemByKey(value);
1940
+ return String(value);
1824
1941
  }
1942
+ /**
1943
+ * Gets the value of an item
1944
+ * @param item Item to get value from
1945
+ * @returns Item value
1946
+ */
1825
1947
  getValue(item) {
1826
- const normalizeItem = this.normalizeItem(item);
1827
- return normalizeItem[this.valueField];
1948
+ const normalizedItem = this.normalizeItem(item);
1949
+ return normalizedItem[this.valueField];
1828
1950
  }
1951
+ /**
1952
+ * Clears the selection cache and selected items
1953
+ */
1829
1954
  clearSelectionCache() {
1830
1955
  this.dataService.cacheList = {};
1831
1956
  this.dataService.selectedItems = [];
1832
1957
  this.cdr.markForCheck();
1833
1958
  }
1959
+ /**
1960
+ * Clears only the cache while preserving selected items
1961
+ */
1834
1962
  softClearSelectionCache() {
1835
1963
  this.dataService.cacheList = {};
1836
1964
  this.cdr.markForCheck();
1837
1965
  }
1966
+ // #endregion
1967
+ // #region Private Helper Methods
1968
+ /**
1969
+ * Asynchronously loads an item by its key and caches the result
1970
+ * @param key Key to load item by
1971
+ */
1972
+ async loadAndCacheItemByKey(key) {
1973
+ try {
1974
+ const item = await this.getItemByKey(key);
1975
+ if (item) {
1976
+ const normalizedItem = this.normalizeItem(item);
1977
+ const cacheKey = this.createCacheKey(String(normalizedItem[this.valueField]));
1978
+ this.dataService.cacheList[cacheKey] = normalizedItem;
1979
+ this.cdr.markForCheck();
1980
+ }
1981
+ }
1982
+ catch (error) {
1983
+ console.warn('Failed to load item by key:', key, error);
1984
+ }
1985
+ }
1838
1986
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: MXSelectionValueComponent, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
1839
1987
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: MXSelectionValueComponent }); }
1840
1988
  }