valtech-components 2.0.392 → 2.0.394

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Component, Input, Output, Injectable, inject, InjectionToken, Inject, ChangeDetectorRef, HostListener, Pipe, ChangeDetectionStrategy, ViewChild, signal, computed, forwardRef, effect } from '@angular/core';
2
+ import { EventEmitter, Component, Input, Output, Injectable, inject, InjectionToken, Inject, ChangeDetectorRef, HostListener, Pipe, ChangeDetectionStrategy, ViewChild, forwardRef } from '@angular/core';
3
3
  import { IonAvatar, IonCard, IonIcon, IonButton, IonSpinner, IonText, IonModal, IonHeader, IonToolbar, IonContent, IonButtons, IonTitle, IonProgressBar, IonCardContent, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCheckbox, IonTextarea, IonDatetime, IonDatetimeButton, IonInput, IonSelect, IonSelectOption, IonLabel, IonSearchbar, IonRadioGroup, IonRadio, IonMenuButton, IonFooter, IonList, IonListHeader, IonNote, IonItem } from '@ionic/angular/standalone';
4
4
  import * as i1 from '@angular/common';
5
5
  import { CommonModule, NgStyle, Location, AsyncPipe, NgFor, NgClass } from '@angular/common';
@@ -5670,45 +5670,13 @@ class MultiSelectSimpleComponent {
5670
5670
  this.valueProperty = 'id';
5671
5671
  this.placeholder = '';
5672
5672
  this.langService = inject(LangService);
5673
- // Signals for reactive state management
5674
- this.isOpen = signal(false);
5675
- this.searchTerm = signal('');
5676
- this.selectedValues = signal([]);
5677
- // Computed signals
5678
- this.displayValue = computed(() => {
5679
- const selected = this.selectedValues();
5680
- if (selected.length === 0) {
5681
- return '';
5682
- }
5683
- if (selected.length === 1) {
5684
- const option = this.getOptionByValue(selected[0]);
5685
- return option ? option[this.labelProperty] : '';
5686
- }
5687
- return `${selected.length} elementos seleccionados`;
5688
- });
5689
- this.filteredOptions = computed(() => {
5690
- const options = this.props?.options || [];
5691
- const search = this.searchTerm().toLowerCase();
5692
- // Debug
5693
- console.log('[MultiSelectSimple] filteredOptions computed:', {
5694
- optionsCount: options.length,
5695
- searchTerm: search,
5696
- options: options.slice(0, 3) // Primeras 3 opciones
5697
- });
5698
- if (!search) {
5699
- return options;
5700
- }
5701
- return options.filter(option => {
5702
- const label = option[this.labelProperty]
5703
- ? replaceSpecialChars(String(option[this.labelProperty]).toLowerCase())
5704
- : '';
5705
- const value = option[this.valueProperty]
5706
- ? replaceSpecialChars(String(option[this.valueProperty]).toLowerCase())
5707
- : '';
5708
- const searchTerm = replaceSpecialChars(search);
5709
- return label.includes(searchTerm) || value.includes(searchTerm);
5710
- });
5711
- });
5673
+ this.changeDetector = inject(ChangeDetectorRef);
5674
+ // Classic Angular properties
5675
+ this.isOpen = false;
5676
+ this.searchTerm = '';
5677
+ this.selectedValues = [];
5678
+ this.displayValue = '';
5679
+ this.filteredOptions = [];
5712
5680
  this.searchPlaceholder = '';
5713
5681
  // ControlValueAccessor
5714
5682
  this.onChange = (_value) => { };
@@ -5720,20 +5688,26 @@ class MultiSelectSimpleComponent {
5720
5688
  }
5721
5689
  ngOnInit() {
5722
5690
  this.applyDefaultValue();
5691
+ this.initializeOptions();
5723
5692
  this.syncSelectedValues();
5693
+ this.updateDisplayValue();
5724
5694
  }
5725
5695
  ngOnDestroy() {
5726
5696
  document.removeEventListener('click', this.handleClickOutside.bind(this));
5727
5697
  }
5728
5698
  ngOnChanges(changes) {
5729
5699
  if (changes['props'] && this.props) {
5700
+ this.initializeOptions();
5730
5701
  this.syncSelectedValues();
5702
+ this.updateDisplayValue();
5703
+ this.changeDetector.detectChanges();
5731
5704
  }
5732
5705
  }
5733
5706
  // ControlValueAccessor implementation
5734
5707
  writeValue(value) {
5735
5708
  const valueArray = this.parseValue(value);
5736
- this.selectedValues.set(valueArray);
5709
+ this.selectedValues = valueArray;
5710
+ this.updateDisplayValue();
5737
5711
  }
5738
5712
  registerOnChange(fn) {
5739
5713
  this.onChange = fn;
@@ -5747,8 +5721,8 @@ class MultiSelectSimpleComponent {
5747
5721
  // Component methods
5748
5722
  toggleDropdown(event) {
5749
5723
  event.stopPropagation();
5750
- this.isOpen.update(value => !value);
5751
- if (this.isOpen()) {
5724
+ this.isOpen = !this.isOpen;
5725
+ if (this.isOpen) {
5752
5726
  this.onTouched();
5753
5727
  // Focus search bar when opening
5754
5728
  setTimeout(() => {
@@ -5760,45 +5734,48 @@ class MultiSelectSimpleComponent {
5760
5734
  }
5761
5735
  }
5762
5736
  onSearch(event) {
5763
- this.searchTerm.set(event.detail.value || '');
5737
+ this.searchTerm = event.detail.value || '';
5738
+ this.filterOptions();
5764
5739
  }
5765
5740
  toggleOption(option) {
5766
- const value = String(option[this.valueProperty]); // Convertir a string
5767
- const currentSelected = this.selectedValues();
5741
+ const value = String(option[this.valueProperty]);
5768
5742
  if (this.isSelected(option)) {
5769
5743
  // Remove from selection
5770
- this.selectedValues.set(currentSelected.filter(v => v !== value));
5744
+ this.selectedValues = this.selectedValues.filter(v => v !== value);
5771
5745
  }
5772
5746
  else {
5773
5747
  // Add to selection
5774
- this.selectedValues.set([...currentSelected, value]);
5748
+ this.selectedValues = [...this.selectedValues, value];
5775
5749
  }
5750
+ this.updateDisplayValue();
5776
5751
  this.emitValue();
5777
5752
  }
5778
5753
  selectAll() {
5779
- const allValues = this.filteredOptions().map(option => String(option[this.valueProperty]));
5780
- const currentSelected = this.selectedValues();
5754
+ const allValues = this.filteredOptions.map(option => String(option[this.valueProperty]));
5781
5755
  // Add only new values to avoid duplicates
5782
- const newValues = allValues.filter(value => !currentSelected.includes(value));
5783
- this.selectedValues.set([...currentSelected, ...newValues]);
5756
+ const newValues = allValues.filter(value => !this.selectedValues.includes(value));
5757
+ this.selectedValues = [...this.selectedValues, ...newValues];
5758
+ this.updateDisplayValue();
5784
5759
  this.emitValue();
5785
5760
  }
5786
5761
  clearAll() {
5787
- this.selectedValues.set([]);
5762
+ this.selectedValues = [];
5763
+ this.updateDisplayValue();
5788
5764
  this.emitValue();
5789
5765
  }
5790
5766
  isSelected(option) {
5791
- return this.selectedValues().includes(String(option[this.valueProperty]));
5767
+ return this.selectedValues.includes(String(option[this.valueProperty]));
5792
5768
  }
5793
5769
  trackByFn(_index, option) {
5794
5770
  return option[this.valueProperty];
5795
5771
  }
5796
5772
  handleClickOutside(event) {
5797
- if (this.isOpen() &&
5773
+ if (this.isOpen &&
5798
5774
  !this.mainInputRef?.nativeElement?.contains(event.target) &&
5799
5775
  !this.dropdownRef?.nativeElement?.contains(event.target)) {
5800
- this.isOpen.set(false);
5801
- this.searchTerm.set('');
5776
+ this.isOpen = false;
5777
+ this.searchTerm = '';
5778
+ this.initializeOptions();
5802
5779
  }
5803
5780
  }
5804
5781
  parseValue(value) {
@@ -5812,7 +5789,7 @@ class MultiSelectSimpleComponent {
5812
5789
  return [String(value)];
5813
5790
  }
5814
5791
  emitValue() {
5815
- const value = this.selectedValues().join(',');
5792
+ const value = this.selectedValues.join(',');
5816
5793
  this.onChange(value);
5817
5794
  if (this.props?.control) {
5818
5795
  this.props.control.setValue(value);
@@ -5821,17 +5798,49 @@ class MultiSelectSimpleComponent {
5821
5798
  }
5822
5799
  }
5823
5800
  getOptionByValue(value) {
5824
- return this.props?.options?.find(option => String(option[this.valueProperty]) === String(value));
5801
+ return this.filteredOptions.find(option => String(option[this.valueProperty]) === String(value));
5825
5802
  }
5826
5803
  applyDefaultValue() {
5827
5804
  if (this.props) {
5828
5805
  applyDefaultValueToControl(this.props);
5829
5806
  }
5830
5807
  }
5808
+ initializeOptions() {
5809
+ this.filteredOptions = this.props?.options || [];
5810
+ }
5811
+ filterOptions() {
5812
+ if (!this.searchTerm) {
5813
+ this.initializeOptions();
5814
+ return;
5815
+ }
5816
+ const search = replaceSpecialChars(this.searchTerm.toLowerCase());
5817
+ this.filteredOptions = (this.props?.options || []).filter(option => {
5818
+ const label = option[this.labelProperty]
5819
+ ? replaceSpecialChars(String(option[this.labelProperty]).toLowerCase())
5820
+ : '';
5821
+ const value = option[this.valueProperty]
5822
+ ? replaceSpecialChars(String(option[this.valueProperty]).toLowerCase())
5823
+ : '';
5824
+ return label.includes(search) || value.includes(search);
5825
+ });
5826
+ }
5827
+ updateDisplayValue() {
5828
+ if (this.selectedValues.length === 0) {
5829
+ this.displayValue = '';
5830
+ return;
5831
+ }
5832
+ if (this.selectedValues.length === 1) {
5833
+ const option = this.getOptionByValue(this.selectedValues[0]);
5834
+ this.displayValue = option ? option[this.labelProperty] : '';
5835
+ }
5836
+ else {
5837
+ this.displayValue = `${this.selectedValues.length} elementos seleccionados`;
5838
+ }
5839
+ }
5831
5840
  syncSelectedValues() {
5832
5841
  if (this.props?.control?.value) {
5833
5842
  const valueArray = this.parseValue(this.props.control.value);
5834
- this.selectedValues.set(valueArray);
5843
+ this.selectedValues = valueArray;
5835
5844
  }
5836
5845
  }
5837
5846
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MultiSelectSimpleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
@@ -5847,18 +5856,18 @@ class MultiSelectSimpleComponent {
5847
5856
  <ion-input
5848
5857
  #mainInput
5849
5858
  type="text"
5850
- [value]="displayValue()"
5859
+ [value]="displayValue"
5851
5860
  [placeholder]="props?.placeholder || placeholder"
5852
5861
  readonly
5853
5862
  class="main-input"
5854
- [class.is-open]="isOpen()"
5863
+ [class.is-open]="isOpen"
5855
5864
  />
5856
5865
 
5857
5866
  <!-- Dropdown icon -->
5858
5867
  <ion-icon
5859
5868
  name="chevron-down-outline"
5860
5869
  class="dropdown-icon"
5861
- [class.rotated]="isOpen()"
5870
+ [class.rotated]="isOpen"
5862
5871
  ></ion-icon>
5863
5872
 
5864
5873
  <!-- Hidden input for form control -->
@@ -5872,7 +5881,7 @@ class MultiSelectSimpleComponent {
5872
5881
  <!-- Dropdown overlay -->
5873
5882
  <div
5874
5883
  class="dropdown-overlay"
5875
- [class.visible]="isOpen()"
5884
+ [class.visible]="isOpen"
5876
5885
  #dropdown
5877
5886
  >
5878
5887
  <!-- Search bar -->
@@ -5881,7 +5890,7 @@ class MultiSelectSimpleComponent {
5881
5890
  #searchbar
5882
5891
  [placeholder]="searchPlaceholder"
5883
5892
  (ionInput)="onSearch($event)"
5884
- [value]="searchTerm()"
5893
+ [value]="searchTerm"
5885
5894
  show-clear-button="focus"
5886
5895
  ></ion-searchbar>
5887
5896
  </div>
@@ -5892,7 +5901,7 @@ class MultiSelectSimpleComponent {
5892
5901
  fill="clear"
5893
5902
  size="small"
5894
5903
  (click)="selectAll()"
5895
- [disabled]="filteredOptions().length === 0"
5904
+ [disabled]="filteredOptions.length === 0"
5896
5905
  >
5897
5906
  Seleccionar todos
5898
5907
  </ion-button>
@@ -5901,7 +5910,7 @@ class MultiSelectSimpleComponent {
5901
5910
  size="small"
5902
5911
  color="medium"
5903
5912
  (click)="clearAll()"
5904
- [disabled]="selectedValues().length === 0"
5913
+ [disabled]="selectedValues.length === 0"
5905
5914
  >
5906
5915
  Limpiar
5907
5916
  </ion-button>
@@ -5911,7 +5920,7 @@ class MultiSelectSimpleComponent {
5911
5920
  <div class="options-container">
5912
5921
  <ion-list class="options-list">
5913
5922
  <ion-item
5914
- *ngFor="let option of filteredOptions(); trackBy: trackByFn"
5923
+ *ngFor="let option of filteredOptions; trackBy: trackByFn"
5915
5924
  button
5916
5925
  (click)="toggleOption(option)"
5917
5926
  class="option-item"
@@ -5924,9 +5933,9 @@ class MultiSelectSimpleComponent {
5924
5933
  </ion-item>
5925
5934
 
5926
5935
  <!-- No results message -->
5927
- <ion-item *ngIf="filteredOptions().length === 0" class="no-results">
5936
+ <ion-item *ngIf="filteredOptions.length === 0" class="no-results">
5928
5937
  <ion-label color="medium">
5929
- {{ searchTerm() ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
5938
+ {{ searchTerm ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
5930
5939
  </ion-label>
5931
5940
  </ion-item>
5932
5941
  </ion-list>
@@ -5948,18 +5957,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
5948
5957
  <ion-input
5949
5958
  #mainInput
5950
5959
  type="text"
5951
- [value]="displayValue()"
5960
+ [value]="displayValue"
5952
5961
  [placeholder]="props?.placeholder || placeholder"
5953
5962
  readonly
5954
5963
  class="main-input"
5955
- [class.is-open]="isOpen()"
5964
+ [class.is-open]="isOpen"
5956
5965
  />
5957
5966
 
5958
5967
  <!-- Dropdown icon -->
5959
5968
  <ion-icon
5960
5969
  name="chevron-down-outline"
5961
5970
  class="dropdown-icon"
5962
- [class.rotated]="isOpen()"
5971
+ [class.rotated]="isOpen"
5963
5972
  ></ion-icon>
5964
5973
 
5965
5974
  <!-- Hidden input for form control -->
@@ -5973,7 +5982,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
5973
5982
  <!-- Dropdown overlay -->
5974
5983
  <div
5975
5984
  class="dropdown-overlay"
5976
- [class.visible]="isOpen()"
5985
+ [class.visible]="isOpen"
5977
5986
  #dropdown
5978
5987
  >
5979
5988
  <!-- Search bar -->
@@ -5982,7 +5991,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
5982
5991
  #searchbar
5983
5992
  [placeholder]="searchPlaceholder"
5984
5993
  (ionInput)="onSearch($event)"
5985
- [value]="searchTerm()"
5994
+ [value]="searchTerm"
5986
5995
  show-clear-button="focus"
5987
5996
  ></ion-searchbar>
5988
5997
  </div>
@@ -5993,7 +6002,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
5993
6002
  fill="clear"
5994
6003
  size="small"
5995
6004
  (click)="selectAll()"
5996
- [disabled]="filteredOptions().length === 0"
6005
+ [disabled]="filteredOptions.length === 0"
5997
6006
  >
5998
6007
  Seleccionar todos
5999
6008
  </ion-button>
@@ -6002,7 +6011,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
6002
6011
  size="small"
6003
6012
  color="medium"
6004
6013
  (click)="clearAll()"
6005
- [disabled]="selectedValues().length === 0"
6014
+ [disabled]="selectedValues.length === 0"
6006
6015
  >
6007
6016
  Limpiar
6008
6017
  </ion-button>
@@ -6012,7 +6021,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
6012
6021
  <div class="options-container">
6013
6022
  <ion-list class="options-list">
6014
6023
  <ion-item
6015
- *ngFor="let option of filteredOptions(); trackBy: trackByFn"
6024
+ *ngFor="let option of filteredOptions; trackBy: trackByFn"
6016
6025
  button
6017
6026
  (click)="toggleOption(option)"
6018
6027
  class="option-item"
@@ -6025,9 +6034,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
6025
6034
  </ion-item>
6026
6035
 
6027
6036
  <!-- No results message -->
6028
- <ion-item *ngIf="filteredOptions().length === 0" class="no-results">
6037
+ <ion-item *ngIf="filteredOptions.length === 0" class="no-results">
6029
6038
  <ion-label color="medium">
6030
- {{ searchTerm() ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
6039
+ {{ searchTerm ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
6031
6040
  </ion-label>
6032
6041
  </ion-item>
6033
6042
  </ion-list>
@@ -6765,105 +6774,39 @@ class SelectSearchComponent {
6765
6774
  this.valueProperty = 'id';
6766
6775
  this.placeholder = '';
6767
6776
  this.langService = inject(LangService);
6768
- // Signals for reactive state management
6769
- this.isOpen = signal(false);
6770
- this.searchTerm = signal('');
6771
- this.selectedValue = signal(null);
6772
- // Force options to be reactive
6773
- this.optionsSignal = signal([]);
6774
- // Computed signals
6775
- this.displayValue = computed(() => {
6776
- const value = this.selectedValue();
6777
- if (!value)
6778
- return '';
6779
- const option = this.getOptionByValue(value);
6780
- return option ? option[this.labelProperty] : '';
6781
- });
6782
- this.filteredOptions = computed(() => {
6783
- // Use signal instead of props directly
6784
- const options = this.optionsSignal();
6785
- const search = this.searchTerm().toLowerCase();
6786
- // Debug mejorado
6787
- console.log('[SelectSearch] filteredOptions computed:', {
6788
- optionsCount: options.length,
6789
- searchTerm: search,
6790
- options: options,
6791
- labelProperty: this.labelProperty,
6792
- valueProperty: this.valueProperty,
6793
- propsExists: !!this.props,
6794
- propsOptionsExists: !!this.props?.options,
6795
- propsOptionsLength: this.props?.options?.length || 0,
6796
- firstOptionStructure: options[0] ? {
6797
- [this.labelProperty]: options[0][this.labelProperty],
6798
- [this.valueProperty]: options[0][this.valueProperty],
6799
- typeOfId: typeof options[0][this.valueProperty],
6800
- fullOption: options[0]
6801
- } : 'NO_OPTIONS'
6802
- });
6803
- if (!search) {
6804
- return options;
6805
- }
6806
- return options.filter(option => {
6807
- const label = option[this.labelProperty]
6808
- ? replaceSpecialChars(String(option[this.labelProperty]).toLowerCase())
6809
- : '';
6810
- const value = option[this.valueProperty]
6811
- ? replaceSpecialChars(String(option[this.valueProperty]).toLowerCase())
6812
- : '';
6813
- const searchTerm = replaceSpecialChars(search);
6814
- return label.includes(searchTerm) || value.includes(searchTerm);
6815
- });
6816
- });
6777
+ this.changeDetector = inject(ChangeDetectorRef);
6778
+ // Classic Angular properties
6779
+ this.isOpen = false;
6780
+ this.searchTerm = '';
6781
+ this.selectedValue = null;
6782
+ this.displayValue = '';
6783
+ this.filteredOptions = [];
6817
6784
  this.placeholder = this.langService.getText('_global', 'selectOption', 'Seleccione una opción');
6818
6785
  // Close dropdown when clicking outside
6819
6786
  document.addEventListener('click', this.handleClickOutside.bind(this));
6820
- // Debug effect to track when filteredOptions changes
6821
- effect(() => {
6822
- const options = this.filteredOptions();
6823
- console.log('[SelectSearch] EFFECT - filteredOptions changed:', {
6824
- optionsCount: options.length,
6825
- options: options,
6826
- timestamp: new Date().toLocaleTimeString()
6827
- });
6828
- });
6829
6787
  }
6830
6788
  ngOnInit() {
6831
- console.log('[SelectSearch] ngOnInit:', {
6832
- props: !!this.props,
6833
- options: this.props?.options?.length || 0,
6834
- control: !!this.props?.control
6835
- });
6836
- // Update options signal
6837
- if (this.props?.options) {
6838
- this.optionsSignal.set(this.props.options);
6839
- }
6840
6789
  this.applyDefaultValue();
6790
+ this.initializeOptions();
6841
6791
  this.syncSelectedValue();
6792
+ this.updateDisplayValue();
6842
6793
  }
6843
6794
  ngOnDestroy() {
6844
6795
  document.removeEventListener('click', this.handleClickOutside.bind(this));
6845
6796
  }
6846
6797
  ngOnChanges(changes) {
6847
- console.log('[SelectSearch] ngOnChanges:', {
6848
- hasPropsChange: !!changes['props'],
6849
- props: !!this.props,
6850
- options: this.props?.options?.length || 0,
6851
- propsOptions: this.props?.options
6852
- });
6853
6798
  if (changes['props'] && this.props) {
6854
- // Update options signal when props change
6855
- if (this.props.options) {
6856
- console.log('[SelectSearch] Updating optionsSignal with:', this.props.options);
6857
- this.optionsSignal.set(this.props.options);
6858
- }
6799
+ this.initializeOptions();
6859
6800
  this.syncSelectedValue();
6801
+ this.updateDisplayValue();
6802
+ this.changeDetector.detectChanges();
6860
6803
  }
6861
6804
  }
6862
6805
  // Component methods
6863
6806
  toggleDropdown(event) {
6864
6807
  event.stopPropagation();
6865
- this.isOpen.update(value => !value);
6866
- if (this.isOpen()) {
6808
+ this.isOpen = !this.isOpen;
6809
+ if (this.isOpen) {
6867
6810
  // Focus search bar when opening if available
6868
6811
  setTimeout(() => {
6869
6812
  const searchbar = this.dropdownRef?.nativeElement?.querySelector('ion-searchbar');
@@ -6874,13 +6817,16 @@ class SelectSearchComponent {
6874
6817
  }
6875
6818
  }
6876
6819
  onSearch(event) {
6877
- this.searchTerm.set(event.detail.value || '');
6820
+ this.searchTerm = event.detail.value || '';
6821
+ this.filterOptions();
6878
6822
  }
6879
6823
  selectOption(option) {
6880
- const value = String(option[this.valueProperty]); // Convertir a string
6881
- this.selectedValue.set(value);
6882
- this.isOpen.set(false);
6883
- this.searchTerm.set('');
6824
+ const value = String(option[this.valueProperty]);
6825
+ this.selectedValue = value;
6826
+ this.isOpen = false;
6827
+ this.searchTerm = '';
6828
+ this.updateDisplayValue();
6829
+ this.initializeOptions(); // Reset filter
6884
6830
  // Update form control
6885
6831
  if (this.props?.control) {
6886
6832
  this.props.control.setValue(value);
@@ -6889,21 +6835,49 @@ class SelectSearchComponent {
6889
6835
  }
6890
6836
  }
6891
6837
  isSelected(option) {
6892
- return String(this.selectedValue()) === String(option[this.valueProperty]);
6838
+ return String(this.selectedValue) === String(option[this.valueProperty]);
6893
6839
  }
6894
6840
  trackByFn(_index, option) {
6895
6841
  return option[this.valueProperty];
6896
6842
  }
6897
6843
  handleClickOutside(event) {
6898
- if (this.isOpen() &&
6844
+ if (this.isOpen &&
6899
6845
  !this.mainInputRef?.nativeElement?.contains(event.target) &&
6900
6846
  !this.dropdownRef?.nativeElement?.contains(event.target)) {
6901
- this.isOpen.set(false);
6902
- this.searchTerm.set('');
6847
+ this.isOpen = false;
6848
+ this.searchTerm = '';
6849
+ this.initializeOptions();
6903
6850
  }
6904
6851
  }
6905
6852
  getOptionByValue(value) {
6906
- return this.optionsSignal().find(option => String(option[this.valueProperty]) === String(value));
6853
+ return this.filteredOptions.find(option => String(option[this.valueProperty]) === String(value));
6854
+ }
6855
+ initializeOptions() {
6856
+ this.filteredOptions = this.props?.options || [];
6857
+ }
6858
+ filterOptions() {
6859
+ if (!this.searchTerm) {
6860
+ this.initializeOptions();
6861
+ return;
6862
+ }
6863
+ const search = replaceSpecialChars(this.searchTerm.toLowerCase());
6864
+ this.filteredOptions = (this.props?.options || []).filter(option => {
6865
+ const label = option[this.labelProperty]
6866
+ ? replaceSpecialChars(String(option[this.labelProperty]).toLowerCase())
6867
+ : '';
6868
+ const value = option[this.valueProperty]
6869
+ ? replaceSpecialChars(String(option[this.valueProperty]).toLowerCase())
6870
+ : '';
6871
+ return label.includes(search) || value.includes(search);
6872
+ });
6873
+ }
6874
+ updateDisplayValue() {
6875
+ if (!this.selectedValue) {
6876
+ this.displayValue = '';
6877
+ return;
6878
+ }
6879
+ const option = this.getOptionByValue(this.selectedValue);
6880
+ this.displayValue = option ? option[this.labelProperty] : '';
6907
6881
  }
6908
6882
  applyDefaultValue() {
6909
6883
  if (this.props) {
@@ -6913,15 +6887,17 @@ class SelectSearchComponent {
6913
6887
  debugOptions() {
6914
6888
  console.log('[SelectSearch] DEBUG CLICK:', {
6915
6889
  props: this.props,
6916
- filteredOptions: this.filteredOptions(),
6917
- searchTerm: this.searchTerm(),
6890
+ filteredOptions: this.filteredOptions,
6891
+ searchTerm: this.searchTerm,
6918
6892
  propsOptions: this.props?.options,
6919
- computed: this.filteredOptions()
6893
+ displayValue: this.displayValue,
6894
+ selectedValue: this.selectedValue,
6895
+ isOpen: this.isOpen
6920
6896
  });
6921
6897
  }
6922
6898
  syncSelectedValue() {
6923
6899
  if (this.props?.control?.value) {
6924
- this.selectedValue.set(String(this.props.control.value));
6900
+ this.selectedValue = String(this.props.control.value);
6925
6901
  }
6926
6902
  }
6927
6903
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SelectSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
@@ -6931,18 +6907,18 @@ class SelectSearchComponent {
6931
6907
  <ion-input
6932
6908
  #mainInput
6933
6909
  type="text"
6934
- [value]="displayValue()"
6910
+ [value]="displayValue"
6935
6911
  [placeholder]="props?.placeholder || placeholder"
6936
6912
  readonly
6937
6913
  class="main-input"
6938
- [class.is-open]="isOpen()"
6914
+ [class.is-open]="isOpen"
6939
6915
  />
6940
6916
 
6941
6917
  <!-- Dropdown icon -->
6942
6918
  <ion-icon
6943
6919
  name="chevron-down-outline"
6944
6920
  class="dropdown-icon"
6945
- [class.rotated]="isOpen()"
6921
+ [class.rotated]="isOpen"
6946
6922
  ></ion-icon>
6947
6923
 
6948
6924
  <!-- Hidden input for form control -->
@@ -6956,12 +6932,12 @@ class SelectSearchComponent {
6956
6932
  <!-- Dropdown overlay -->
6957
6933
  <div
6958
6934
  class="dropdown-overlay"
6959
- [class.visible]="isOpen()"
6935
+ [class.visible]="isOpen"
6960
6936
  #dropdown
6961
6937
  >
6962
6938
  <!-- Debug button -->
6963
6939
  <div class="search-container" style="background: red; color: white; padding: 4px;">
6964
- <button (click)="debugOptions()">DEBUG: {{ filteredOptions().length }} opciones</button>
6940
+ <button (click)="debugOptions()">DEBUG: {{ filteredOptions.length }} opciones</button>
6965
6941
  </div>
6966
6942
 
6967
6943
  <!-- Search bar -->
@@ -6970,7 +6946,7 @@ class SelectSearchComponent {
6970
6946
  #searchbar
6971
6947
  [placeholder]="'Buscar'"
6972
6948
  (ionInput)="onSearch($event)"
6973
- [value]="searchTerm()"
6949
+ [value]="searchTerm"
6974
6950
  show-clear-button="focus"
6975
6951
  [debounce]="200"
6976
6952
  ></ion-searchbar>
@@ -6980,7 +6956,7 @@ class SelectSearchComponent {
6980
6956
  <div class="options-container">
6981
6957
  <ion-list class="options-list">
6982
6958
  <ion-item
6983
- *ngFor="let option of filteredOptions(); trackBy: trackByFn"
6959
+ *ngFor="let option of filteredOptions; trackBy: trackByFn"
6984
6960
  button
6985
6961
  (click)="selectOption(option)"
6986
6962
  class="option-item"
@@ -6995,11 +6971,11 @@ class SelectSearchComponent {
6995
6971
  </ion-item>
6996
6972
 
6997
6973
  <!-- No results message -->
6998
- <ion-item *ngIf="filteredOptions().length === 0" class="no-results">
6974
+ <ion-item *ngIf="filteredOptions.length === 0" class="no-results">
6999
6975
  <ion-label color="medium">
7000
- {{ searchTerm() ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
6976
+ {{ searchTerm ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
7001
6977
  <!-- Debug info -->
7002
- <br><small>Debug: {{ filteredOptions().length }} opciones | Props: {{ !!props }} | Search: "{{ searchTerm() }}"</small>
6978
+ <br><small>Debug: {{ filteredOptions.length }} opciones | Props: {{ !!props }} | Search: "{{ searchTerm }}"</small>
7003
6979
  </ion-label>
7004
6980
  </ion-item>
7005
6981
  </ion-list>
@@ -7015,18 +6991,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
7015
6991
  <ion-input
7016
6992
  #mainInput
7017
6993
  type="text"
7018
- [value]="displayValue()"
6994
+ [value]="displayValue"
7019
6995
  [placeholder]="props?.placeholder || placeholder"
7020
6996
  readonly
7021
6997
  class="main-input"
7022
- [class.is-open]="isOpen()"
6998
+ [class.is-open]="isOpen"
7023
6999
  />
7024
7000
 
7025
7001
  <!-- Dropdown icon -->
7026
7002
  <ion-icon
7027
7003
  name="chevron-down-outline"
7028
7004
  class="dropdown-icon"
7029
- [class.rotated]="isOpen()"
7005
+ [class.rotated]="isOpen"
7030
7006
  ></ion-icon>
7031
7007
 
7032
7008
  <!-- Hidden input for form control -->
@@ -7040,12 +7016,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
7040
7016
  <!-- Dropdown overlay -->
7041
7017
  <div
7042
7018
  class="dropdown-overlay"
7043
- [class.visible]="isOpen()"
7019
+ [class.visible]="isOpen"
7044
7020
  #dropdown
7045
7021
  >
7046
7022
  <!-- Debug button -->
7047
7023
  <div class="search-container" style="background: red; color: white; padding: 4px;">
7048
- <button (click)="debugOptions()">DEBUG: {{ filteredOptions().length }} opciones</button>
7024
+ <button (click)="debugOptions()">DEBUG: {{ filteredOptions.length }} opciones</button>
7049
7025
  </div>
7050
7026
 
7051
7027
  <!-- Search bar -->
@@ -7054,7 +7030,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
7054
7030
  #searchbar
7055
7031
  [placeholder]="'Buscar'"
7056
7032
  (ionInput)="onSearch($event)"
7057
- [value]="searchTerm()"
7033
+ [value]="searchTerm"
7058
7034
  show-clear-button="focus"
7059
7035
  [debounce]="200"
7060
7036
  ></ion-searchbar>
@@ -7064,7 +7040,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
7064
7040
  <div class="options-container">
7065
7041
  <ion-list class="options-list">
7066
7042
  <ion-item
7067
- *ngFor="let option of filteredOptions(); trackBy: trackByFn"
7043
+ *ngFor="let option of filteredOptions; trackBy: trackByFn"
7068
7044
  button
7069
7045
  (click)="selectOption(option)"
7070
7046
  class="option-item"
@@ -7079,11 +7055,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
7079
7055
  </ion-item>
7080
7056
 
7081
7057
  <!-- No results message -->
7082
- <ion-item *ngIf="filteredOptions().length === 0" class="no-results">
7058
+ <ion-item *ngIf="filteredOptions.length === 0" class="no-results">
7083
7059
  <ion-label color="medium">
7084
- {{ searchTerm() ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
7060
+ {{ searchTerm ? 'No se encontraron resultados' : 'No hay opciones disponibles' }}
7085
7061
  <!-- Debug info -->
7086
- <br><small>Debug: {{ filteredOptions().length }} opciones | Props: {{ !!props }} | Search: "{{ searchTerm() }}"</small>
7062
+ <br><small>Debug: {{ filteredOptions.length }} opciones | Props: {{ !!props }} | Search: "{{ searchTerm }}"</small>
7087
7063
  </ion-label>
7088
7064
  </ion-item>
7089
7065
  </ion-list>
@@ -8294,6 +8270,7 @@ class FormComponent {
8294
8270
  section.fields
8295
8271
  .filter(x => x.type === this.types.SELECT || x.type === this.types.TEXT || x.type === this.types.SEARCH_SELECT || x.type === this.types.MULTI_SELECT || x.type === this.types.MULTI_SELECT_SIMPLE)
8296
8272
  .forEach(field => {
8273
+ console.log(`[FormComponent] Tracking changes for field: ${field.name}, type: ${field.type}`);
8297
8274
  this.trackSelectChanges(field.name);
8298
8275
  });
8299
8276
  });
@@ -8304,15 +8281,27 @@ class FormComponent {
8304
8281
  }
8305
8282
  trackSelectChanges(fieldName) {
8306
8283
  const control = this.getControl(fieldName);
8284
+ // Initialize previous value
8285
+ this.previousValues.set(fieldName, control.value);
8307
8286
  const subscription = control.valueChanges
8308
8287
  .pipe(distinctUntilChanged$1()) // Evitar valores duplicados
8309
8288
  .subscribe(value => {
8289
+ console.log(`[FormComponent] valueChanges for ${fieldName}:`, {
8290
+ field: fieldName,
8291
+ newValue: value,
8292
+ previousValue: this.previousValues.get(fieldName),
8293
+ willEmit: this.previousValues.get(fieldName) !== value
8294
+ });
8310
8295
  // Evitar loops - solo emitir si el valor realmente cambió
8311
8296
  const previousValue = this.previousValues.get(fieldName);
8312
8297
  if (previousValue !== value) {
8313
8298
  this.previousValues.set(fieldName, value);
8299
+ console.log(`[FormComponent] EMITTING onSelectChange:`, { field: fieldName, value });
8314
8300
  this.onSelectChange.emit({ field: fieldName, value });
8315
8301
  }
8302
+ else {
8303
+ console.log(`[FormComponent] SKIPPING emit - same value for ${fieldName}`);
8304
+ }
8316
8305
  });
8317
8306
  this.subscriptions.push(subscription);
8318
8307
  }
@@ -8379,6 +8368,19 @@ class FormComponent {
8379
8368
  data: this.props,
8380
8369
  };
8381
8370
  }
8371
+ // Helper method to reset field value without triggering change event
8372
+ resetField(fieldName, emitEvent = false) {
8373
+ const control = this.getControl(fieldName);
8374
+ const currentValue = control.value;
8375
+ console.log(`[FormComponent] Resetting field ${fieldName}:`, { currentValue, emitEvent });
8376
+ // Update our cache to avoid triggering change event
8377
+ if (!emitEvent) {
8378
+ this.previousValues.set(fieldName, '');
8379
+ }
8380
+ control.setValue('', { emitEvent });
8381
+ control.markAsPristine();
8382
+ control.markAsUntouched();
8383
+ }
8382
8384
  get actions() {
8383
8385
  if (!this.form) {
8384
8386
  return [];