import { Component, EventEmitter, Input, Output, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { Observable, of } from 'rxjs'; import { combineLatestWith, map, startWith } from 'rxjs/operators'; import { MatOption, MatOptionSelectionChange } from '@angular/material/core'; import { IOption } from './interfaces/option.interface'; import { AbstractControl, ValidationErrors } from '@angular/forms'; import { ChevronDown, X, CircleAlert } from 'lucide-angular'; @Component({ selector: 'kit-select', templateUrl: './select.component.html', styleUrls: ['../styles/index.scss'], }) export class SelectComponent implements OnInit , OnChanges{ @Input() control: any; @Input() options: IOption[] = []; @Input() placeholderText: string = ''; @Input() isLoading = false; @Input() label: string = ''; @Input() isMultipleSelect = false; @Input() iconClear:string =""; @Input() descriptionTooltip: string = ''; @Output() changeEvent: EventEmitter> = new EventEmitter(); public filteredOptions$: Observable | undefined; readonly chevronDownI = ChevronDown; readonly xI = X; readonly infoCircle = CircleAlert; ngOnInit(): void { this.setFilterObservable() } ngOnChanges(changes: SimpleChanges): void { if(changes['options']) { this.setFilterObservable() } } isControlRequired(): boolean { if(this.control && this.control.validator) { const validator = this.control.validator({} as any); return !!(validator && validator.required); } return false } private setFilterObservable(){ this.filteredOptions$ = this.control.valueChanges.pipe( startWith(this.control.value || ''), combineLatestWith(of(this.options || [])), map(([inputValue, optionslist]) => { if(inputValue){ let filterValue: string; if (typeof inputValue === 'object' && inputValue) { filterValue = inputValue.value ? inputValue.value.toLowerCase() : ''; } else if (typeof inputValue === 'string') { filterValue = inputValue.toLowerCase(); } else { filterValue = ''; } if (!filterValue) { return optionslist; } return optionslist.filter((option: any) => option.value.toLowerCase().includes(filterValue) || // Filtra por value option.label.toLowerCase().includes(filterValue) // O por label ); } else { return optionslist; } }) ); if (this.options && this.options.length > 0 ) { const existingValidators = this.control.validator ? [this.control.validator] : []; this.control.setValidators([this.validateOption.bind(this), ...existingValidators]) } } displayFn(option: IOption): string { return option && option.label ? option.label : ''; } clearSelection(){ this.control.setValue(null); this.changeEvent.emit(); } private validateOption(control: AbstractControl): ValidationErrors|null { const value = control.value; // Valida si el valor es un objeto o un primitivo y si está en las opciones if(this.options && value) { const isValid = this.options?.some(option => typeof value === 'object' ? option.value === value.value : option.value === value ); return isValid ? null : { invalidOption: true }; } return null } onChange(event: MatOptionSelectionChange) { this.changeEvent.emit(event.source.value); } }