@guajiritos/general-autocomplete 19.0.3 → 19.0.5
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.
@@ -95,9 +95,8 @@ class GuajiritosGeneralAutocomplete {
|
|
95
95
|
this._zone = _zone;
|
96
96
|
this._destroyRef = _destroyRef;
|
97
97
|
this.translateService = translateService;
|
98
|
-
// ---
|
99
|
-
// Indica si la última actualización del input fue por una selección explícita desde el
|
100
|
-
this._isOptionSelected = false;
|
98
|
+
// --- Propiedades Privadas ---
|
99
|
+
this._isOptionSelected = false; // Indica si la última actualización del input fue por una selección explícita desde el autocompletado
|
101
100
|
this._clearDataSubject = new Subject();
|
102
101
|
this._doFocusSubject = new Subject();
|
103
102
|
this._selectedElement = null; // Almacena el objeto completo seleccionado
|
@@ -105,8 +104,8 @@ class GuajiritosGeneralAutocomplete {
|
|
105
104
|
this._limit = 20;
|
106
105
|
this._offset = 0;
|
107
106
|
this._restrictionsFilters = [];
|
108
|
-
this._lastSearchText = ""; // Almacena el texto usado en la última búsqueda de API
|
109
|
-
// ---
|
107
|
+
this._lastSearchText = ""; // Almacena el texto usado en la última búsqueda de API exitosa
|
108
|
+
// --- Señales Públicas (Signals) ---
|
110
109
|
this.disabled = signal(false);
|
111
110
|
this.loading = signal(false);
|
112
111
|
this.required = signal(false);
|
@@ -140,10 +139,10 @@ class GuajiritosGeneralAutocomplete {
|
|
140
139
|
// --- Outputs ---
|
141
140
|
this.selectElement = new EventEmitter();
|
142
141
|
this.clearElement = new EventEmitter();
|
143
|
-
// --- ControlValueAccessor
|
142
|
+
// --- Métodos de ControlValueAccessor ---
|
144
143
|
this.propagateChange = (_) => { };
|
145
144
|
/**
|
146
|
-
*
|
145
|
+
* Función para mostrar los elementos seleccionados
|
147
146
|
*/
|
148
147
|
this.displayFn = (value) => {
|
149
148
|
if (!value) {
|
@@ -167,7 +166,7 @@ class GuajiritosGeneralAutocomplete {
|
|
167
166
|
return displayText;
|
168
167
|
};
|
169
168
|
}
|
170
|
-
// --- Setters
|
169
|
+
// --- Setters para Inputs ---
|
171
170
|
set url(data) {
|
172
171
|
if (data) {
|
173
172
|
this._url = data;
|
@@ -186,10 +185,7 @@ class GuajiritosGeneralAutocomplete {
|
|
186
185
|
.pipe(takeUntilDestroyed(this._destroyRef))
|
187
186
|
.subscribe({
|
188
187
|
next: () => {
|
189
|
-
this.
|
190
|
-
this.component.setValue(null, { emitEvent: false }); // No emitir para evitar ciclo de valueChanges
|
191
|
-
this.propagateChange(null);
|
192
|
-
this.selectElement.emit(null);
|
188
|
+
this.clearInternalState();
|
193
189
|
},
|
194
190
|
});
|
195
191
|
}
|
@@ -206,26 +202,32 @@ class GuajiritosGeneralAutocomplete {
|
|
206
202
|
// Actualizar _lastSearchText basado en el valor inicial
|
207
203
|
if (value) {
|
208
204
|
this._lastSearchText = this.displayFn(value);
|
209
|
-
console.log("initialValue
|
205
|
+
console.log("initialValue establecido: _lastSearchText =", this._lastSearchText);
|
210
206
|
}
|
211
207
|
else {
|
212
208
|
this._lastSearchText = "";
|
213
209
|
}
|
214
210
|
}
|
215
211
|
/**
|
216
|
-
*
|
212
|
+
* Añade o elimina restricciones de búsqueda
|
217
213
|
*/
|
218
214
|
set restrictions(restrictions) {
|
219
215
|
this._restrictionsFilters = restrictions?.length ? [...restrictions] : [];
|
216
|
+
// Siempre resetear el estado cuando cambian las restricciones
|
220
217
|
this.resetAutocompleteState();
|
221
|
-
// Re-ejecutar búsqueda si el input tiene texto y hay restricciones
|
218
|
+
// Re-ejecutar búsqueda si el input tiene texto o si está vacío y no hay selección, o si las restricciones cambiaron realmente el resultado esperado.
|
222
219
|
const currentSearchText = this.getAutocompleteSearchText();
|
223
|
-
|
220
|
+
// Sólo si ya había un texto o una selección, o si las restricciones realmente impactan la búsqueda inicial.
|
221
|
+
if (currentSearchText !== this._lastSearchText ||
|
222
|
+
(!currentSearchText && !this._selectedElement) ||
|
223
|
+
restrictions?.length > 0) {
|
224
|
+
console.log("Restricciones cambiadas, iniciando nueva búsqueda.");
|
225
|
+
// No actualizar _lastSearchText aquí, se actualiza después de la API.
|
224
226
|
this.getAutocompleteByTextHandler(currentSearchText);
|
225
227
|
}
|
226
228
|
}
|
227
229
|
/**
|
228
|
-
*
|
230
|
+
* Añade o elimina la validación de requerido
|
229
231
|
*/
|
230
232
|
set isRequired(required) {
|
231
233
|
this.required.set(required);
|
@@ -237,7 +239,7 @@ class GuajiritosGeneralAutocomplete {
|
|
237
239
|
this.component.updateValueAndValidity();
|
238
240
|
}
|
239
241
|
/**
|
240
|
-
*
|
242
|
+
* Define si se realiza una búsqueda cuando el elemento está en foco
|
241
243
|
*/
|
242
244
|
set doFocus(focusSubject) {
|
243
245
|
this._doFocusSubject = focusSubject;
|
@@ -249,11 +251,14 @@ class GuajiritosGeneralAutocomplete {
|
|
249
251
|
this._zone.run(() => {
|
250
252
|
setTimeout(() => {
|
251
253
|
this.inputText?.nativeElement?.focus();
|
252
|
-
//
|
253
|
-
//
|
254
|
-
this.
|
255
|
-
|
256
|
-
|
254
|
+
// Simular evento 'input' para disparar valueChanges, pero solo si el input está vacío
|
255
|
+
// o si ya hay un valor pero no es el seleccionado (usuario queriendo buscar de nuevo).
|
256
|
+
if (!this.component.value ||
|
257
|
+
(typeof this.component.value === "string" &&
|
258
|
+
!this._selectedElement)) {
|
259
|
+
this.inputText?.nativeElement?.dispatchEvent(new Event("input"));
|
260
|
+
}
|
261
|
+
this.autocompleteTrigger?.openPanel();
|
257
262
|
}, 50); // Un pequeño retraso para asegurar el foco y la apertura
|
258
263
|
});
|
259
264
|
},
|
@@ -266,77 +271,92 @@ class GuajiritosGeneralAutocomplete {
|
|
266
271
|
}
|
267
272
|
}
|
268
273
|
/**
|
269
|
-
*
|
270
|
-
*
|
274
|
+
* Reinicia el estado de paginación y opciones del autocompletado.
|
275
|
+
* Centraliza la lógica para evitar duplicación.
|
271
276
|
*/
|
272
277
|
resetAutocompleteState() {
|
273
278
|
this._offset = 0;
|
274
279
|
this.originalOptions.set([]);
|
275
280
|
this.filteredOptions.set([]);
|
276
281
|
this.hasMore.set(true);
|
277
|
-
|
278
|
-
// _lastSearchText se actualiza en writeValue y optionSelected
|
279
|
-
console.log("Autocomplete state reset (pagination/options).");
|
282
|
+
console.log("Estado de autocompletado reiniciado (paginación/opciones).");
|
280
283
|
}
|
281
284
|
/**
|
282
|
-
*
|
285
|
+
* Suscripción a los cambios del input de búsqueda
|
283
286
|
*/
|
284
287
|
subscribeToComponentChanges() {
|
285
288
|
this.component.valueChanges
|
286
289
|
.pipe(
|
287
|
-
//
|
290
|
+
// TAP se ejecuta inmediatamente ANTES del debounce.
|
291
|
+
// Esto es crucial para detectar borrados de texto en tiempo real y desvincular _selectedElement.
|
288
292
|
tap((value) => {
|
289
|
-
|
290
|
-
//
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
293
|
+
const currentInputText = this.getAutocompleteSearchText();
|
294
|
+
// Si el valor actual del control es un STRING (usuario escribiendo/borrando)
|
295
|
+
// Y previamente había un objeto seleccionado (_selectedElement)
|
296
|
+
// Y el texto en el input ya no coincide con el displayFn del _selectedElement,
|
297
|
+
// entonces desvinculamos el _selectedElement y marcamos que no hay selección.
|
298
|
+
if (typeof value === "string" &&
|
299
|
+
this._selectedElement &&
|
300
|
+
currentInputText !== this.displayFn(this._selectedElement)) {
|
301
|
+
console.log("TAP: El usuario está editando/borrando texto de un elemento seleccionado. Deseleccionando internamente.");
|
302
|
+
this._selectedElement = null; // Quitar la referencia al objeto seleccionado
|
303
|
+
this._isOptionSelected = false; // Marcar que no hay una opción seleccionada
|
304
|
+
}
|
305
|
+
else if (typeof value === "string") {
|
306
|
+
// Si el valor es un string, simplemente marcamos que no hay opción seleccionada.
|
307
|
+
// Esto cubre los casos donde el usuario escribe por primera vez o borra sin haber seleccionado.
|
296
308
|
this._isOptionSelected = false;
|
297
|
-
return; // Salir del tap, el debounce/switchMap no se ejecutará para este valor.
|
298
309
|
}
|
299
|
-
}), debounceTime(this.debounceTimeValue),
|
310
|
+
}), debounceTime(this.debounceTimeValue), // El debounce se aplica después de la lógica del tap
|
311
|
+
takeUntilDestroyed(this._destroyRef))
|
300
312
|
.subscribe({
|
301
313
|
next: (value) => {
|
302
314
|
const currentSearchText = this.getAutocompleteSearchText();
|
303
|
-
//
|
304
|
-
//
|
305
|
-
if (typeof value === "object" &&
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
315
|
+
// Caso 1: El valor es un objeto y coincide con el elemento seleccionado.
|
316
|
+
// Esto ocurre si el usuario seleccionó un elemento y el debounce pasó sin más ediciones.
|
317
|
+
if (typeof value === "object" &&
|
318
|
+
value !== null &&
|
319
|
+
this._selectedElement === value) {
|
320
|
+
console.log("El valor es un objeto seleccionado (después de debounce), saltando la búsqueda.");
|
321
|
+
// Aseguramos que el _lastSearchText esté correcto para este objeto.
|
322
|
+
this._lastSearchText = this.displayFn(value);
|
323
|
+
return;
|
312
324
|
}
|
313
|
-
//
|
314
|
-
//
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
(
|
319
|
-
) {
|
320
|
-
this.resetAutocompleteState(); // Reiniciar paginación y opciones
|
321
|
-
this._lastSearchText = currentSearchText; // Actualizar el último texto buscado
|
322
|
-
console.log("Value changed, initiating new search for:", currentSearchText);
|
325
|
+
// Caso 2: El usuario ha terminado de escribir o borrar texto.
|
326
|
+
// Si el texto actual ha cambiado con respecto al último buscado.
|
327
|
+
if (currentSearchText !== this._lastSearchText) {
|
328
|
+
this.resetAutocompleteState(); // Reiniciar paginación y opciones para la nueva búsqueda
|
329
|
+
this._lastSearchText = currentSearchText; // Actualizar el último texto buscado ANTES de la llamada a la API
|
330
|
+
console.log("El valor ha cambiado (después de debounce), iniciando nueva búsqueda para:", currentSearchText);
|
323
331
|
this.getAutocompleteByTextHandler(currentSearchText);
|
332
|
+
// Propagar el valor del input al control externo si no hay un elemento seleccionado
|
333
|
+
// y el texto no está vacío, o si está vacío y no hay selección.
|
334
|
+
if (!this._selectedElement && currentSearchText !== "") {
|
335
|
+
this.propagateChange(currentSearchText);
|
336
|
+
}
|
337
|
+
else if (!this._selectedElement && currentSearchText === "") {
|
338
|
+
this.propagateChange(null);
|
339
|
+
}
|
324
340
|
}
|
325
|
-
else
|
326
|
-
|
327
|
-
//
|
341
|
+
else {
|
342
|
+
console.log("El valor no ha cambiado o es un estado estable, saltando nueva búsqueda de valueChanges.");
|
343
|
+
// Si el texto es el mismo, pero el panel está abierto, sin opciones y hay más datos potenciales,
|
344
|
+
// podemos necesitar una recarga (ej. si una búsqueda anterior falló o la red fue lenta).
|
328
345
|
if (this.matAutocomplete._isOpen &&
|
329
346
|
this.originalOptions().length === 0 &&
|
330
|
-
!this.loading()
|
331
|
-
|
332
|
-
|
347
|
+
!this.loading() &&
|
348
|
+
this.hasMore() &&
|
349
|
+
currentSearchText === "" // Solo si el input está vacío y no hay opciones
|
350
|
+
) {
|
351
|
+
console.log("Input sin cambios pero panel abierto/vacío, activando re-búsqueda.");
|
352
|
+
this.getAutocompleteByTextHandler(currentSearchText);
|
333
353
|
}
|
334
354
|
}
|
335
355
|
},
|
336
356
|
});
|
337
357
|
}
|
338
358
|
ngAfterViewInit() {
|
339
|
-
// Suscribirse a la apertura del panel para añadir el listener de scroll
|
359
|
+
// Suscribirse a la apertura del panel para añadir el listener de scroll y cargar datos
|
340
360
|
this.matAutocomplete.opened
|
341
361
|
.pipe(takeUntilDestroyed(this._destroyRef))
|
342
362
|
.subscribe(() => {
|
@@ -344,14 +364,31 @@ class GuajiritosGeneralAutocomplete {
|
|
344
364
|
// Asegurarse de que el listener sea removido antes de añadirlo para prevenir duplicados
|
345
365
|
this.matAutocomplete.panel.nativeElement.removeEventListener("scroll", this.onScroll.bind(this));
|
346
366
|
this.matAutocomplete.panel.nativeElement.addEventListener("scroll", this.onScroll.bind(this));
|
347
|
-
// Si el panel se abre y no hay opciones cargadas, o si el input está vacío
|
348
|
-
// y no hay una selección activa, cargar las opciones iniciales.
|
349
367
|
const currentSearchText = this.getAutocompleteSearchText();
|
350
|
-
|
351
|
-
|
352
|
-
|
368
|
+
// **********************************************
|
369
|
+
// MODIFICACIÓN CLAVE AQUÍ:
|
370
|
+
// Cargar opciones iniciales SOLO SI:
|
371
|
+
// 1. No hay opciones cargadas (primera apertura o después de un clear/reset).
|
372
|
+
// 2. O el texto actual en el input es diferente del _lastSearchText (el usuario escribió algo nuevo o borró y abrió).
|
373
|
+
// 3. O el input está vacío Y no hay un _selectedElement Y hay más datos por cargar Y el offset es 0 (lo que implica que es la primera carga para este estado vacío).
|
374
|
+
// Esto evita la doble llamada si subscribeToComponentChanges ya disparó una búsqueda
|
375
|
+
// para el mismo texto, o si ya se sabe que no hay más datos para un input vacío.
|
376
|
+
// **********************************************
|
377
|
+
if (this.originalOptions().length === 0 || // No hay opciones, cargar siempre.
|
378
|
+
currentSearchText !== this._lastSearchText || // El texto ha cambiado, nueva búsqueda.
|
379
|
+
(currentSearchText === "" &&
|
380
|
+
!this._selectedElement &&
|
381
|
+
this.hasMore() &&
|
382
|
+
this._offset === 0) // Input vacío, sin selección, con potencial de datos, y es la primera carga.
|
383
|
+
) {
|
384
|
+
console.log("Panel abierto, condiciones cumplidas para búsqueda inicial/nueva. Cargando conjunto inicial de opciones.");
|
385
|
+
this.resetAutocompleteState(); // Asegurarse de resetear antes de una nueva carga
|
386
|
+
this._lastSearchText = currentSearchText; // Sincronizar _lastSearchText con la búsqueda que se va a realizar
|
353
387
|
this.getAutocompleteByTextHandler(currentSearchText);
|
354
388
|
}
|
389
|
+
else {
|
390
|
+
console.log("Panel abierto, opciones ya cargadas o elemento seleccionado existe, o texto sin cambios. Saltando carga inicial.");
|
391
|
+
}
|
355
392
|
}
|
356
393
|
});
|
357
394
|
// Suscribirse al cierre del panel para remover el listener de scroll y manejar la deselección
|
@@ -363,110 +400,122 @@ class GuajiritosGeneralAutocomplete {
|
|
363
400
|
}
|
364
401
|
const currentInputValue = this.component.value;
|
365
402
|
const currentInputText = this.getAutocompleteSearchText();
|
366
|
-
console.log("
|
403
|
+
console.log("Autocompletado cerrado. Valor actual del Input:", currentInputValue, "Elemento seleccionado:", this._selectedElement, "Texto actual del Input:", currentInputText);
|
367
404
|
// Lógica para manejar el borrado del input si no hay una selección válida
|
368
405
|
// o si el texto no coincide con el elemento seleccionado.
|
369
406
|
if (typeof currentInputValue === "string") {
|
370
|
-
// Si el
|
371
|
-
if (this.
|
372
|
-
|
373
|
-
//
|
374
|
-
if (!this._selectedElement ||
|
375
|
-
currentInputText !== this.displayFn(this._selectedElement)) {
|
376
|
-
console.warn("Autocomplete closed: Input cleared because selection is required and no valid match found.");
|
377
|
-
this.clearInternalState(); // Usa un método para limpiar
|
378
|
-
}
|
407
|
+
// Si el input está vacío Y no hay un elemento seleccionado
|
408
|
+
if (currentInputText === "" && !this._selectedElement) {
|
409
|
+
console.log("Autocompletado cerrado: Input vacío y sin selección. Limpiando estado interno.");
|
410
|
+
this.clearInternalState(); // Usa un método para limpiar
|
379
411
|
}
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
currentInputText !== this.displayFn(this._selectedElement)) {
|
385
|
-
|
386
|
-
|
387
|
-
this.component.setValue(this._selectedElement, {
|
388
|
-
emitEvent: false,
|
389
|
-
});
|
390
|
-
this._lastSearchText = this.displayFn(this._selectedElement);
|
391
|
-
this.propagateChange(this._selectedElement); // Propagar el valor original si se revierte
|
392
|
-
}
|
393
|
-
else if (currentInputText === "" && this._selectedElement) {
|
394
|
-
// Si el input está vacío pero había un elemento seleccionado, deseleccionar
|
395
|
-
console.log("Autocomplete closed: Input cleared by user, deselecting element.");
|
396
|
-
this.clearInternalState();
|
397
|
-
}
|
398
|
-
else if (currentInputText === "" && !this._selectedElement) {
|
399
|
-
// Si el input está vacío y no había selección, simplemente asegúrate de que el estado interno refleje esto.
|
400
|
-
console.log("Autocomplete closed: Input empty, no selection.");
|
401
|
-
this.clearInternalState(); // Asegura el estado
|
402
|
-
}
|
403
|
-
// Si el texto del input es un string y no se requiere selección,
|
404
|
-
// y no hay _selectedElement, asumimos que el usuario quiere el texto libre.
|
405
|
-
// No hacemos nada, el texto permanece.
|
406
|
-
if (typeof currentInputValue === "string" &&
|
407
|
-
!this.requireSelection &&
|
408
|
-
!this._selectedElement) {
|
409
|
-
// Si no hay un elemento seleccionado pero el usuario escribió algo
|
410
|
-
// y no se requiere selección, dejamos el texto tal cual.
|
411
|
-
// Aseguramos que _lastSearchText se actualice para evitar re-búsquedas innecesarias.
|
412
|
-
this._lastSearchText = currentInputText;
|
413
|
-
this.propagateChange(currentInputText);
|
414
|
-
}
|
412
|
+
// Si se requiere selección y el texto no coincide con el elemento seleccionado,
|
413
|
+
// o no hay ningún elemento seleccionado, entonces se borra.
|
414
|
+
else if (this.requireSelection &&
|
415
|
+
(!this._selectedElement ||
|
416
|
+
currentInputText !== this.displayFn(this._selectedElement))) {
|
417
|
+
console.warn("Autocompletado cerrado: Selección requerida y no se encontró una coincidencia válida. Limpiando input.");
|
418
|
+
this.clearInternalState(); // Usa un método para limpiar
|
415
419
|
}
|
420
|
+
// Si NO se requiere selección, pero el usuario ha editado el texto de un elemento previamente seleccionado.
|
421
|
+
// En este caso, NO borramos, sino que revertimos al texto del elemento seleccionado si existe.
|
422
|
+
else if (this._selectedElement &&
|
423
|
+
currentInputText !== this.displayFn(this._selectedElement) &&
|
424
|
+
!this.requireSelection) {
|
425
|
+
console.log("Autocompletado cerrado: Texto editado para un elemento seleccionado, revirtiendo al original.");
|
426
|
+
// Revertir al texto del elemento seleccionado.
|
427
|
+
this.component.setValue(this._selectedElement, {
|
428
|
+
emitEvent: false,
|
429
|
+
});
|
430
|
+
this._lastSearchText = this.displayFn(this._selectedElement);
|
431
|
+
this.propagateChange(this._selectedElement); // Propagar el valor original si se revierte
|
432
|
+
}
|
433
|
+
// Si el texto del input es un string y no se requiere selección,
|
434
|
+
// y no hay _selectedElement (porque se deseleccionó en el tap o nunca hubo),
|
435
|
+
// asumimos que el usuario quiere el texto libre.
|
436
|
+
// No hacemos nada, el texto permanece.
|
437
|
+
else if (typeof currentInputValue === "string" &&
|
438
|
+
!this.requireSelection &&
|
439
|
+
!this._selectedElement &&
|
440
|
+
currentInputText !== "") {
|
441
|
+
// Si no hay un elemento seleccionado pero el usuario escribió algo
|
442
|
+
// y no se requiere selección, dejamos el texto tal cual.
|
443
|
+
// Aseguramos que _lastSearchText se actualice para evitar re-búsquedas innecesarias.
|
444
|
+
this._lastSearchText = currentInputText;
|
445
|
+
this.propagateChange(currentInputText);
|
446
|
+
}
|
447
|
+
}
|
448
|
+
// Si el valor ya es un objeto (porque se seleccionó) pero el texto del input fue borrado
|
449
|
+
// y el _selectedElement es null (ya se desvinculó en el tap), significa que debe limpiarse.
|
450
|
+
else if (typeof currentInputValue === "object" &&
|
451
|
+
currentInputText === "" &&
|
452
|
+
!this._selectedElement) {
|
453
|
+
console.log("Autocompletado cerrado: Valor de objeto pero input limpiado por el usuario. Deseleccionando.");
|
454
|
+
this.clearInternalState();
|
416
455
|
}
|
417
|
-
// Si el valor ya es un objeto (porque se seleccionó), no hacemos nada aquí
|
418
|
-
// a menos que el usuario haya borrado manualmente el texto del input.
|
419
|
-
// Esa última parte se cubre con la condición currentInputText === ""
|
420
456
|
});
|
421
457
|
}
|
422
458
|
/**
|
423
|
-
*
|
459
|
+
* Método auxiliar para limpiar el estado interno del autocompletado.
|
460
|
+
* Este método ahora se encarga de la limpieza profunda, incluyendo el valor del FormControl y la propagación.
|
461
|
+
* @param resetLastSearchText - Si es true, reinicia _lastSearchText a una cadena vacía. Por defecto es true.
|
424
462
|
*/
|
425
|
-
clearInternalState() {
|
426
|
-
|
463
|
+
clearInternalState(resetLastSearchText = true) {
|
464
|
+
// Solo si el valor del control NO es null, lo seteamos a null para evitar bucles.
|
465
|
+
// Esto es importante porque en el tap, solo desvinculamos `_selectedElement` pero no el control.
|
466
|
+
if (this.component.value !== null) {
|
467
|
+
this.component.setValue(null, { emitEvent: false });
|
468
|
+
}
|
427
469
|
this.propagateChange(null);
|
428
470
|
this.selectElement.emit(null);
|
429
|
-
this._selectedElement = null;
|
430
|
-
this.
|
471
|
+
this._selectedElement = null; // Asegurar que el objeto seleccionado esté a null
|
472
|
+
this._isOptionSelected = false; // Asegurar que la bandera de selección esté a false
|
473
|
+
if (resetLastSearchText) {
|
474
|
+
this._lastSearchText = "";
|
475
|
+
}
|
431
476
|
this.resetAutocompleteState(); // Resetear opciones y paginación
|
432
|
-
console.log("
|
477
|
+
console.log("Estado interno del autocompletado limpiado.");
|
433
478
|
}
|
434
479
|
/**
|
435
|
-
*
|
436
|
-
*
|
437
|
-
* @param text -
|
480
|
+
* Busca elementos para mostrar en el componente de autocompletado.
|
481
|
+
* Ahora soporta paginación.
|
482
|
+
* @param text - Texto a buscar
|
438
483
|
*/
|
439
484
|
getAutocompleteByTextHandler(text) {
|
440
|
-
|
441
|
-
//
|
442
|
-
if (
|
443
|
-
|
444
|
-
text === this._lastSearchText && // Verificar que el texto de búsqueda actual sea el mismo
|
445
|
-
!this.loading()) {
|
446
|
-
console.log("No more data for current search text, stopping further loads.");
|
485
|
+
const currentSearchText = text ?? "";
|
486
|
+
// Si ya estamos cargando, salimos para evitar peticiones duplicadas.
|
487
|
+
if (this.loading()) {
|
488
|
+
console.log("Ya estamos cargando, saliendo de getAutocompleteByTextHandler.");
|
447
489
|
return;
|
448
490
|
}
|
449
|
-
|
450
|
-
|
491
|
+
// **********************************************
|
492
|
+
// CLAVE: Evitar búsquedas innecesarias cuando ya se sabe que no hay más datos
|
493
|
+
// para el texto actual.
|
494
|
+
// Importante: Esto no debe detener la primera carga (offset 0).
|
495
|
+
// **********************************************
|
496
|
+
if (!this.hasMore() && // No hay más datos
|
497
|
+
this._offset > 0 && // Ya se cargó algo antes
|
498
|
+
currentSearchText === this._lastSearchText // El mismo texto de búsqueda para el que ya se agotaron los resultados
|
499
|
+
) {
|
500
|
+
console.log("No hay más datos para el texto de búsqueda actual, deteniendo cargas adicionales.");
|
451
501
|
return;
|
452
502
|
}
|
453
503
|
this.loading.set(true);
|
454
504
|
const currentOffset = this._offset; // Capturar el offset actual antes de la llamada
|
455
|
-
const currentSearchTextForApi = text; // Usar el texto pasado, no el global _lastSearchText
|
456
505
|
if (!this._url && !this.serviceConfig) {
|
457
|
-
console.warn("
|
506
|
+
console.warn("Autocompletado: Se requiere el input 'url' o 'serviceConfig'.");
|
458
507
|
this.loading.set(false);
|
459
508
|
this.hasMore.set(false);
|
460
509
|
return;
|
461
510
|
}
|
462
511
|
let apiCall;
|
463
512
|
if (this._url) {
|
464
|
-
apiCall = from(this._autocompleteService.getAutocompleteByText(this._url,
|
513
|
+
apiCall = from(this._autocompleteService.getAutocompleteByText(this._url, currentSearchText, // Usar el texto de búsqueda actual
|
465
514
|
this.filterString, this._restrictionsFilters, this.removeProperties, this.order, this.bodyRequest, { limit: this._limit, offset: currentOffset })).pipe(switchMap((innerObservable) => innerObservable));
|
466
515
|
}
|
467
516
|
else if (this.serviceConfig) {
|
468
517
|
let body = { ...this.serviceConfig };
|
469
|
-
body[this.serviceConfig.searchProperty] =
|
518
|
+
body[this.serviceConfig.searchProperty] = currentSearchText; // Usar el texto de búsqueda actual
|
470
519
|
body["limit"] = this._limit;
|
471
520
|
body["offset"] = currentOffset;
|
472
521
|
apiCall = this.serviceConfig.service[this.serviceConfig.method](body);
|
@@ -488,22 +537,31 @@ class GuajiritosGeneralAutocomplete {
|
|
488
537
|
.subscribe({
|
489
538
|
next: (result) => {
|
490
539
|
const newData = result?.payload?.data ?? result?.data ?? [];
|
491
|
-
console.log("
|
540
|
+
console.log("Nuevos datos recibidos:", newData.length, "elementos. Offset actual antes de la actualización:", this._offset);
|
541
|
+
// Si el offset es 0 (primera carga para esta búsqueda), reemplazamos las opciones.
|
542
|
+
// De lo contrario, las añadimos.
|
543
|
+
// Esto maneja que cada nueva búsqueda reemplace los resultados anteriores,
|
544
|
+
// y el scroll añada a los existentes.
|
545
|
+
if (currentOffset === 0) {
|
546
|
+
this.originalOptions.set(newData);
|
547
|
+
console.log("Primera carga para este texto. Opciones originales reemplazadas.");
|
548
|
+
}
|
549
|
+
else {
|
550
|
+
this.originalOptions.update((currentOptions) => [
|
551
|
+
...currentOptions,
|
552
|
+
...newData,
|
553
|
+
]);
|
554
|
+
console.log("Carga adicional por scroll. Opciones originales actualizadas.");
|
555
|
+
}
|
492
556
|
this._offset += newData.length; // Actualizar offset con la cantidad de nuevos ítems
|
493
557
|
if (newData.length < this._limit) {
|
494
558
|
this.hasMore.set(false);
|
495
|
-
console.log("No
|
559
|
+
console.log("No hay más datos, hasMore = false");
|
496
560
|
}
|
497
561
|
else {
|
498
562
|
this.hasMore.set(true);
|
499
|
-
console.log("
|
563
|
+
console.log("Potencialmente más datos, hasMore = true");
|
500
564
|
}
|
501
|
-
// Actualizar las opciones originales
|
502
|
-
this.originalOptions.update((currentOptions) => {
|
503
|
-
const updatedOptions = [...currentOptions, ...newData];
|
504
|
-
console.log("Total options after merge:", updatedOptions.length);
|
505
|
-
return updatedOptions;
|
506
|
-
});
|
507
565
|
this.filterOptionsBasedOnNotAllowed();
|
508
566
|
// Restaurar la posición de scroll después de que Angular haya actualizado el DOM
|
509
567
|
// Esto debe hacerse fuera de la zona de Angular o con un pequeño retardo.
|
@@ -512,13 +570,13 @@ class GuajiritosGeneralAutocomplete {
|
|
512
570
|
setTimeout(() => {
|
513
571
|
this.matAutocomplete.panel.nativeElement.scrollTop =
|
514
572
|
panelScrollTop;
|
515
|
-
console.log("
|
573
|
+
console.log("Posición de scroll restaurada a:", panelScrollTop);
|
516
574
|
}, 0); // Un pequeño retardo para asegurar que el DOM se haya renderizado
|
517
575
|
});
|
518
576
|
}
|
519
577
|
},
|
520
578
|
error: (error) => {
|
521
|
-
console.error("Error
|
579
|
+
console.error("Error al obtener datos de autocompletado:", error);
|
522
580
|
this.loading.set(false);
|
523
581
|
this.hasMore.set(false);
|
524
582
|
},
|
@@ -538,7 +596,7 @@ class GuajiritosGeneralAutocomplete {
|
|
538
596
|
}
|
539
597
|
}
|
540
598
|
/**
|
541
|
-
*
|
599
|
+
* Define el texto a utilizar para la búsqueda
|
542
600
|
*/
|
543
601
|
getAutocompleteSearchText() {
|
544
602
|
const value = this.component.value;
|
@@ -568,13 +626,14 @@ class GuajiritosGeneralAutocomplete {
|
|
568
626
|
: value
|
569
627
|
: null;
|
570
628
|
// Actualizar _lastSearchText basado en el valor que se está escribiendo.
|
629
|
+
// Si el valor es nulo, _lastSearchText también debe ser nulo o vacío
|
571
630
|
if (value) {
|
572
631
|
this._lastSearchText = this.displayFn(value);
|
573
|
-
console.log("writeValue:
|
632
|
+
console.log("writeValue: Último texto de búsqueda establecido a:", this._lastSearchText);
|
574
633
|
}
|
575
634
|
else {
|
576
635
|
this._lastSearchText = "";
|
577
|
-
console.log("writeValue:
|
636
|
+
console.log("writeValue: Último texto de búsqueda limpiado.");
|
578
637
|
}
|
579
638
|
}
|
580
639
|
setDisabledState(isDisabled) {
|
@@ -587,16 +646,11 @@ class GuajiritosGeneralAutocomplete {
|
|
587
646
|
}
|
588
647
|
}
|
589
648
|
/**
|
590
|
-
*
|
649
|
+
* Acción al limpiar el valor del input
|
591
650
|
*/
|
592
651
|
clear(trigger) {
|
593
652
|
this.clearElement.emit(this.component.value);
|
594
653
|
this.clearInternalState(); // Usa el método auxiliar para limpiar
|
595
|
-
// this.component.setValue(null); // Ya se llama dentro de clearInternalState
|
596
|
-
// this.propagateChange(null);
|
597
|
-
// this.selectElement.emit(null);
|
598
|
-
// this._selectedElement = null;
|
599
|
-
// this._lastSearchText = "";
|
600
654
|
this._zone.run(() => {
|
601
655
|
setTimeout(() => {
|
602
656
|
trigger.openPanel(); // Reabrir el panel después de borrar
|
@@ -605,24 +659,15 @@ class GuajiritosGeneralAutocomplete {
|
|
605
659
|
});
|
606
660
|
}
|
607
661
|
/**
|
608
|
-
*
|
662
|
+
* Acción al enfocar el elemento
|
609
663
|
*/
|
610
664
|
onFocus() {
|
611
|
-
|
612
|
-
//
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
console.log("On focus, initiating search for:", currentSearchText);
|
618
|
-
this.getAutocompleteByTextHandler(currentSearchText);
|
619
|
-
}
|
620
|
-
else if (this.matAutocomplete._isOpen &&
|
621
|
-
currentSearchText === this._lastSearchText) {
|
622
|
-
// Si el panel ya está abierto y el texto no ha cambiado, no hacer nada para evitar re-cargas innecesarias.
|
623
|
-
// Si el panel no estaba abierto, la apertura de `matAutocomplete.opened` se encargará de la carga.
|
624
|
-
console.log("On focus, panel already open with same text, skipping search.");
|
625
|
-
}
|
665
|
+
console.log("On focus: El panel será abierto por el trigger.");
|
666
|
+
// NOTA CLAVE: Ya NO disparamos getAutocompleteByTextHandler aquí directamente.
|
667
|
+
// La lógica de carga inicial cuando el panel se abre se gestiona
|
668
|
+
// en la suscripción a `this.matAutocomplete.opened` en `ngAfterViewInit`.
|
669
|
+
// Esto es crucial para evitar doble disparo, especialmente en dispositivos táctiles.
|
670
|
+
// El openPanel() lo maneja el trigger en el HTML, lo cual a su vez dispara matAutocomplete.opened.
|
626
671
|
}
|
627
672
|
optionSelected($event) {
|
628
673
|
const selectedValue = $event?.option?.value;
|
@@ -639,37 +684,26 @@ class GuajiritosGeneralAutocomplete {
|
|
639
684
|
// Cuando un ítem es seleccionado, actualizar _lastSearchText con su valor de display.
|
640
685
|
// Esto es crucial para que el valueChanges no vuelva a disparar una búsqueda para este valor.
|
641
686
|
this._lastSearchText = this.displayFn(selectedValue);
|
642
|
-
console.log("
|
687
|
+
console.log("Opción seleccionada. Último texto de búsqueda establecido a:", this._lastSearchText);
|
643
688
|
}
|
644
689
|
else {
|
645
690
|
// Si se deselecciona o selecciona nulo
|
646
|
-
|
647
|
-
console.log("Option selected is null or undefined, clearing state.");
|
691
|
+
console.log("La opción seleccionada es nula o indefinida, limpiando el estado.");
|
648
692
|
this.clearInternalState();
|
649
693
|
}
|
650
|
-
// Después de la selección, el panel se cierra automáticamente en la mayoría de los casos de MatAutocomplete.
|
651
|
-
// this.matAutocomplete.closePanel(); // Descomentar si el panel no se cierra automáticamente
|
652
694
|
}
|
653
695
|
/**
|
654
|
-
*
|
696
|
+
* Maneja el evento de scroll en el panel del autocompletado para cargar más datos.
|
655
697
|
*/
|
656
698
|
onScroll(event) {
|
657
699
|
const element = event.target;
|
658
700
|
const scrollPosition = element.scrollTop + element.clientHeight;
|
659
701
|
const scrollHeight = element.scrollHeight;
|
660
|
-
const threshold = 50; //
|
661
|
-
// console.log("--- Scroll Event ---");
|
662
|
-
// console.log("Scroll Top:", element.scrollTop);
|
663
|
-
// console.log("Client Height:", element.clientHeight);
|
664
|
-
// console.log("Scroll Position (Top + Client):", scrollPosition);
|
665
|
-
// console.log("Scroll Height (Total):", scrollHeight);
|
666
|
-
// console.log("Remaining distance to bottom:", scrollHeight - scrollPosition);
|
667
|
-
// console.log("Is Loading:", this.loading());
|
668
|
-
// console.log("Has More:", this.hasMore());
|
702
|
+
const threshold = 50; // Píxeles antes del final para cargar más
|
669
703
|
if (scrollHeight - scrollPosition <= threshold &&
|
670
704
|
!this.loading() &&
|
671
705
|
this.hasMore()) {
|
672
|
-
console.log("
|
706
|
+
console.log("Cargando más datos por scroll infinito...");
|
673
707
|
// Usar el texto de búsqueda actual (que puede ser el texto del ítem seleccionado o lo que el usuario escribió)
|
674
708
|
this.getAutocompleteByTextHandler(this.getAutocompleteSearchText());
|
675
709
|
}
|
@@ -681,7 +715,7 @@ class GuajiritosGeneralAutocomplete {
|
|
681
715
|
useExisting: forwardRef(() => GuajiritosGeneralAutocomplete),
|
682
716
|
multi: true,
|
683
717
|
},
|
684
|
-
], viewQueries: [{ propertyName: "inputText", first: true, predicate: ["inputText"], descendants: true, static: true }, { propertyName: "matAutocomplete", first: true, predicate: ["auto"], descendants: true }, { propertyName: "autocompleteTrigger", first: true, predicate: MatAutocompleteTrigger, descendants: true }], ngImport: i0, template: "<mat-form-field
|
718
|
+
], viewQueries: [{ propertyName: "inputText", first: true, predicate: ["inputText"], descendants: true, static: true }, { propertyName: "matAutocomplete", first: true, predicate: ["auto"], descendants: true }, { propertyName: "autocompleteTrigger", first: true, predicate: MatAutocompleteTrigger, descendants: true }], ngImport: i0, template: "<mat-form-field\n [floatLabel]=\"floatLabel\"\n class=\"w-100\"\n [appearance]=\"appearance\"\n [color]=\"color\"\n [subscriptSizing]=\"subscriptSizing\"\n>\n @if (showLabel) {\n <mat-label>{{ label | translate }}</mat-label>\n } @if (showSuffix) {\n <mat-icon matSuffix>{{ suffixIcon ?? \"search\" }}</mat-icon>\n }\n <input\n #inputText\n #trigger=\"matAutocompleteTrigger\"\n (focus)=\"onFocus()\"\n [formControl]=\"component\"\n type=\"text\"\n [matAutocomplete]=\"auto\"\n [placeholder]=\"placeholder | translate\"\n aria-label=\"autocomplete\"\n autocomplete=\"off\"\n matInput\n [required]=\"required()\"\n />\n @if (!loading() && component.value) {\n <button\n (click)=\"clear(trigger)\"\n [disabled]=\"disabled()\"\n aria-label=\"Clear\"\n mat-icon-button\n matSuffix\n >\n <mat-icon>close</mat-icon>\n </button>\n } @if (loading()) {\n <button aria-label=\"search\" mat-icon-button matSuffix>\n <mat-spinner [value]=\"90\" color=\"accent\" diameter=\"25\"></mat-spinner>\n </button>\n }\n <mat-autocomplete\n #auto=\"matAutocomplete\"\n [displayWith]=\"displayFn\"\n [requireSelection]=\"requireSelection\"\n (optionSelected)=\"optionSelected($event)\"\n >\n @for (option of filteredOptions(); track option) {\n <mat-option [value]=\"option\">\n @if (!displayOptions && !detailsTemplate) {\n {{ option?.name | i18n: translateService.currentLang }}\n } @if (!detailsTemplate) {\n <div class=\"display-options\">\n <span [ngStyle]=\"{'line-height': displayOptions?.secondLabel ? '16px' : ''}\">\n {{\n option | resolvePropertyPath : displayOptions.firthLabel\n | i18n : translateService.currentLang\n }}\n </span>\n @if (displayOptions?.secondLabel) {\n <span class=\"mat-caption\">\n {{\n option | resolvePropertyPath : displayOptions.secondLabel\n | i18n : translateService.currentLang\n }}\n </span>\n }\n </div>\n } @if (detailsTemplate) {\n <ng-container\n *ngTemplateOutlet=\"detailsTemplate; context: { $implicit: option }\"\n ></ng-container>\n }\n </mat-option>\n }\n </mat-autocomplete>\n\n @if (component.invalid && component.touched) {\n <mat-error>\n {{ 'Este campo es requerido.' | translate }}\n </mat-error>\n }\n</mat-form-field>\n", styles: [".w-100{width:100%}.display-options{display:flex;flex-direction:column;justify-content:flex-start;align-items:flex-start}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i6.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i6.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i8.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i9.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i10.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i10.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i10.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "pipe", type: I18nPipe, name: "i18n" }, { kind: "pipe", type: ResolvePropertyPath, name: "resolvePropertyPath" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
685
719
|
}
|
686
720
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: GuajiritosGeneralAutocomplete, decorators: [{
|
687
721
|
type: Component,
|
@@ -703,7 +737,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImpo
|
|
703
737
|
useExisting: forwardRef(() => GuajiritosGeneralAutocomplete),
|
704
738
|
multi: true,
|
705
739
|
},
|
706
|
-
], template: "<mat-form-field
|
740
|
+
], template: "<mat-form-field\n [floatLabel]=\"floatLabel\"\n class=\"w-100\"\n [appearance]=\"appearance\"\n [color]=\"color\"\n [subscriptSizing]=\"subscriptSizing\"\n>\n @if (showLabel) {\n <mat-label>{{ label | translate }}</mat-label>\n } @if (showSuffix) {\n <mat-icon matSuffix>{{ suffixIcon ?? \"search\" }}</mat-icon>\n }\n <input\n #inputText\n #trigger=\"matAutocompleteTrigger\"\n (focus)=\"onFocus()\"\n [formControl]=\"component\"\n type=\"text\"\n [matAutocomplete]=\"auto\"\n [placeholder]=\"placeholder | translate\"\n aria-label=\"autocomplete\"\n autocomplete=\"off\"\n matInput\n [required]=\"required()\"\n />\n @if (!loading() && component.value) {\n <button\n (click)=\"clear(trigger)\"\n [disabled]=\"disabled()\"\n aria-label=\"Clear\"\n mat-icon-button\n matSuffix\n >\n <mat-icon>close</mat-icon>\n </button>\n } @if (loading()) {\n <button aria-label=\"search\" mat-icon-button matSuffix>\n <mat-spinner [value]=\"90\" color=\"accent\" diameter=\"25\"></mat-spinner>\n </button>\n }\n <mat-autocomplete\n #auto=\"matAutocomplete\"\n [displayWith]=\"displayFn\"\n [requireSelection]=\"requireSelection\"\n (optionSelected)=\"optionSelected($event)\"\n >\n @for (option of filteredOptions(); track option) {\n <mat-option [value]=\"option\">\n @if (!displayOptions && !detailsTemplate) {\n {{ option?.name | i18n: translateService.currentLang }}\n } @if (!detailsTemplate) {\n <div class=\"display-options\">\n <span [ngStyle]=\"{'line-height': displayOptions?.secondLabel ? '16px' : ''}\">\n {{\n option | resolvePropertyPath : displayOptions.firthLabel\n | i18n : translateService.currentLang\n }}\n </span>\n @if (displayOptions?.secondLabel) {\n <span class=\"mat-caption\">\n {{\n option | resolvePropertyPath : displayOptions.secondLabel\n | i18n : translateService.currentLang\n }}\n </span>\n }\n </div>\n } @if (detailsTemplate) {\n <ng-container\n *ngTemplateOutlet=\"detailsTemplate; context: { $implicit: option }\"\n ></ng-container>\n }\n </mat-option>\n }\n </mat-autocomplete>\n\n @if (component.invalid && component.touched) {\n <mat-error>\n {{ 'Este campo es requerido.' | translate }}\n </mat-error>\n }\n</mat-form-field>\n", styles: [".w-100{width:100%}.display-options{display:flex;flex-direction:column;justify-content:flex-start;align-items:flex-start}\n"] }]
|
707
741
|
}], ctorParameters: () => [{ type: i1.AutocompleteService }, { type: i0.NgZone }, { type: i0.DestroyRef }, { type: i2.TranslateService }], propDecorators: { inputText: [{
|
708
742
|
type: ViewChild,
|
709
743
|
args: ["inputText", { static: true }]
|
@@ -779,16 +813,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImpo
|
|
779
813
|
type: Input
|
780
814
|
}] } });
|
781
815
|
/**
|
782
|
-
*
|
816
|
+
* Validación personalizada para la selección de elementos
|
783
817
|
*/
|
784
818
|
function autocompleteValidator(control) {
|
785
819
|
// Un valor válido es un objeto no nulo que tiene una propiedad 'id'.
|
786
|
-
// Esto asegura que realmente se ha seleccionado un objeto del
|
820
|
+
// Esto asegura que realmente se ha seleccionado un objeto del autocompletado, no solo texto libre.
|
821
|
+
// Si el control está vacío, no se aplica esta validación aquí, sino la de 'Validators.required' si está presente.
|
822
|
+
if (control.value === null ||
|
823
|
+
typeof control.value === "undefined" ||
|
824
|
+
control.value === "") {
|
825
|
+
return null; // Deja que Validators.required maneje si está vacío.
|
826
|
+
}
|
787
827
|
if (typeof control?.value === "object" &&
|
788
828
|
control?.value !== null &&
|
789
829
|
"id" in control.value) {
|
790
830
|
return null;
|
791
831
|
}
|
832
|
+
// Si el valor es una cadena (texto libre) y debería ser un objeto seleccionado.
|
792
833
|
return { invalidSelection: true };
|
793
834
|
}
|
794
835
|
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"guajiritos-general-autocomplete.mjs","sources":["../../../projects/guachos-general-autocomplete/src/utils/constants/constants.ts","../../../projects/guachos-general-autocomplete/src/utils/services/utils.service.ts","../../../projects/guachos-general-autocomplete/src/utils/pipes/resolve-property-path.pipe.ts","../../../projects/guachos-general-autocomplete/src/lib/guachos-general-autocomplete.component.ts","../../../projects/guachos-general-autocomplete/src/lib/guachos-general-autocomplete.component.html","../../../projects/guachos-general-autocomplete/src/public-api.ts","../../../projects/guachos-general-autocomplete/src/guajiritos-general-autocomplete.ts"],"sourcesContent":["import { DisplayOption, DisplayOptionItemType } from '@guajiritos/services';\nimport {DisplayOptionItem} from \"@guajiritos/services/lib/interfaces/interfaces\";\n\n\nexport const GENERAL_DISPLAY_OPTIONS: DisplayOption = {\n firthLabel: [\n {\n type: DisplayOptionItemType.PATH,\n path: ['name']\n }\n ],\n applyTranslate: true\n};\n\nexport interface ServiceConfig {\n service: any;\n method: string;\n postBody: any;\n searchProperty: string;\n}\n","import {Injectable} from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class UtilsService {\n /**\n * Resolves the value of a property in an object by providing a path.\n *\n * @param {any} obj - The object to traverse.\n * @param {string[]} path - An array of strings representing the path to the desired property.\n * @return {any} The value of the property at the given path, or null if the path is invalid.\n */\n public static resolvePropertyByPath(obj: any, path: string[]): any {\n return path.reduce((prev, curr: string) => {\n return prev ? prev[curr] : null;\n }, obj || self);\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\nimport { DisplayOptionItem, DisplayOptionItemType } from '@guajiritos/services';\n\nimport { UtilsService } from '../services/utils.service';\n\n@Pipe({\n name: 'resolvePropertyPath',\n standalone: true\n})\nexport class ResolvePropertyPath implements PipeTransform {\n /**\n * Transforms the given object based on the provided path and returns the transformed string.\n *\n * @param {any} obj - The object to be transformed.\n * @param {DisplayOptionItem[]} path - The array of display option items used for transformation.\n * @return {string} The transformed string.\n */\n transform(obj: any, path: DisplayOptionItem[]): string {\n let result: string = '';\n\n path?.forEach((item: DisplayOptionItem): void => {\n if (item?.type === DisplayOptionItemType.DIVIDER) {\n result += item?.divider;\n } else {\n if (item?.path) {\n result += UtilsService.resolvePropertyByPath(obj, item.path);\n }\n }\n });\n\n return result;\n }\n}\n","import { CommonModule } from \"@angular/common\";\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n EventEmitter,\n forwardRef,\n Input,\n NgZone,\n Output,\n signal,\n TemplateRef,\n ViewChild,\n WritableSignal,\n} from \"@angular/core\";\nimport {\n AbstractControl,\n ControlValueAccessor,\n NG_VALUE_ACCESSOR,\n ReactiveFormsModule,\n UntypedFormControl,\n ValidationErrors,\n ValidatorFn,\n Validators,\n} from \"@angular/forms\";\nimport {\n MatAutocomplete,\n MatAutocompleteModule,\n MatAutocompleteTrigger,\n} from \"@angular/material/autocomplete\";\nimport { MatButtonModule } from \"@angular/material/button\";\nimport { ThemePalette } from \"@angular/material/core\";\nimport {\n FloatLabelType,\n MatFormFieldAppearance,\n MatFormFieldModule,\n SubscriptSizing,\n} from \"@angular/material/form-field\";\nimport { MatIconModule } from \"@angular/material/icon\";\nimport { MatInputModule } from \"@angular/material/input\";\nimport { MatProgressSpinnerModule } from \"@angular/material/progress-spinner\";\nimport { TranslateModule, TranslateService } from \"@ngx-translate/core\";\nimport {\n debounceTime,\n finalize,\n Observable,\n Subject,\n from,\n switchMap,\n tap,\n} from \"rxjs\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\n\nimport {\n ApiFormData,\n AutocompleteService,\n DisplayOption,\n DisplayOptionItemType,\n I18nPipe,\n RestrictionFilter,\n} from \"@guajiritos/services\";\n\nimport {\n GENERAL_DISPLAY_OPTIONS,\n ServiceConfig,\n} from \"../utils/constants/constants\";\nimport { ResolvePropertyPath } from \"../utils/pipes/resolve-property-path.pipe\";\nimport { UtilsService } from \"../utils/services/utils.service\";\n\n@Component({\n selector: \"guajiritos-general-autocomplete\",\n templateUrl: \"./guachos-general-autocomplete.component.html\",\n styleUrls: [\"./guachos-general-autocomplete.component.scss\"],\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n imports: [\n CommonModule,\n MatFormFieldModule,\n TranslateModule,\n MatIconModule,\n ReactiveFormsModule,\n MatInputModule,\n MatButtonModule,\n MatProgressSpinnerModule,\n MatAutocompleteModule,\n I18nPipe,\n ResolvePropertyPath,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => GuajiritosGeneralAutocomplete),\n multi: true,\n },\n ],\n})\nexport class GuajiritosGeneralAutocomplete\n implements ControlValueAccessor, AfterViewInit\n{\n constructor(\n private _autocompleteService: AutocompleteService,\n private _zone: NgZone,\n private _destroyRef: DestroyRef,\n public translateService: TranslateService,\n ) {}\n\n // --- Private Properties ---\n // Indica si la última actualización del input fue por una selección explícita desde el autocomplete\n private _isOptionSelected: boolean = false;\n private _clearDataSubject: Subject<void> = new Subject<void>();\n private _doFocusSubject: Subject<void> = new Subject<void>();\n private _selectedElement: any = null; // Almacena el objeto completo seleccionado\n private _url: string | null = null;\n private _limit: number = 20;\n private _offset: number = 0;\n private _restrictionsFilters: RestrictionFilter[] = [];\n private _lastSearchText: string = \"\"; // Almacena el texto usado en la última búsqueda de API\n\n // --- Public Signals ---\n public disabled: WritableSignal<boolean> = signal(false);\n public loading: WritableSignal<boolean> = signal(false);\n public required: WritableSignal<boolean> = signal(false);\n public filteredOptions: WritableSignal<any[]> = signal([]);\n public originalOptions: WritableSignal<any[]> = signal([]);\n public notAllowedOption: WritableSignal<any> = signal(null);\n public component: UntypedFormControl = new UntypedFormControl({\n value: null,\n disabled: false,\n });\n public hasMore: WritableSignal<boolean> = signal(true); // Indica si hay más datos para cargar\n\n // --- ViewChildren ---\n @ViewChild(\"inputText\", { static: true }) inputText!: ElementRef;\n @ViewChild(\"auto\") matAutocomplete!: MatAutocomplete;\n @ViewChild(MatAutocompleteTrigger)\n autocompleteTrigger!: MatAutocompleteTrigger;\n // --- Inputs ---\n @Input() floatLabel: FloatLabelType = \"auto\";\n @Input() color: ThemePalette = \"accent\";\n @Input() appearance: MatFormFieldAppearance = \"outline\";\n @Input() subscriptSizing: SubscriptSizing = \"dynamic\";\n @Input() bodyRequest?: ApiFormData;\n @Input() debounceTimeValue: number = 300;\n @Input() detailsTemplate?: TemplateRef<any>;\n @Input() label: string = \"Seleccione\";\n @Input() showLabel: boolean = true;\n @Input() placeholder: string = \"Seleccione un elemento\";\n @Input() field: string[] = [\"name\"];\n @Input() filterString: string[] | string = \"filter[$and][name][$like]\";\n @Input() displayOptions: DisplayOption = GENERAL_DISPLAY_OPTIONS;\n @Input() withoutPaddingBottom: boolean = true;\n @Input() valueId: boolean = false;\n @Input() showSuffix: boolean = false;\n @Input() requireSelection: boolean = false;\n @Input() order?: string;\n @Input() serviceConfig?: ServiceConfig;\n @Input() suffixIcon: string = \"search\";\n @Input() removeProperties: string[] = [];\n @Input() modifyResultFn: (options: any[]) => any[] = (options: any[]) =>\n options;\n\n // --- Outputs ---\n @Output() selectElement: EventEmitter<any> = new EventEmitter<any>();\n @Output() clearElement: EventEmitter<any> = new EventEmitter<any>();\n\n // --- Setters for Inputs ---\n @Input() set url(data: string) {\n if (data) {\n this._url = data;\n // Suscribirse a los cambios del componente una vez que la URL está disponible\n this.subscribeToComponentChanges();\n }\n }\n\n @Input() set limit(value: number) {\n if (value && !isNaN(value)) {\n this._limit = value;\n }\n }\n\n @Input() set clearData(value: Subject<void>) {\n this._clearDataSubject = value;\n this._clearDataSubject\n .pipe(takeUntilDestroyed(this._destroyRef))\n .subscribe({\n next: (): void => {\n this.resetAutocompleteState();\n this.component.setValue(null, { emitEvent: false }); // No emitir para evitar ciclo de valueChanges\n this.propagateChange(null);\n this.selectElement.emit(null);\n },\n });\n }\n\n @Input() set initialValue(value: any) {\n // Si el valor inicial es el mismo que el valor actual del control, no hacer nada para evitar bucles\n if (value === this.component.value) {\n return;\n }\n\n this._selectedElement = value;\n this._isOptionSelected = !!value; // Marcar como seleccionado si hay un valor inicial\n\n // Establecer el valor en el formControl sin emitir el evento\n // para evitar que subscribeToComponentChanges reaccione a esta carga inicial.\n this.component.setValue(value, { emitEvent: false });\n\n // Actualizar _lastSearchText basado en el valor inicial\n if (value) {\n this._lastSearchText = this.displayFn(value);\n console.log(\"initialValue set: _lastSearchText =\", this._lastSearchText);\n } else {\n this._lastSearchText = \"\";\n }\n }\n\n /**\n * Adds or removes search restrictions\n */\n @Input() set restrictions(restrictions: RestrictionFilter[]) {\n this._restrictionsFilters = restrictions?.length ? [...restrictions] : [];\n this.resetAutocompleteState();\n // Re-ejecutar búsqueda si el input tiene texto y hay restricciones\n const currentSearchText = this.getAutocompleteSearchText();\n if (currentSearchText) {\n this.getAutocompleteByTextHandler(currentSearchText);\n }\n }\n\n /**\n * Adds or removes required validation\n */\n @Input() set isRequired(required: boolean) {\n this.required.set(required);\n const validators: ValidatorFn[] = [autocompleteValidator];\n if (required) {\n validators.push(Validators.required);\n }\n this.component.setValidators(validators);\n this.component.updateValueAndValidity();\n }\n\n /**\n * Defines whether to perform a search when the element is in focus\n */\n @Input() set doFocus(focusSubject: Subject<void>) {\n this._doFocusSubject = focusSubject;\n this._doFocusSubject\n .pipe(\n debounceTime(this.debounceTimeValue), // Retrasar para evitar llamadas excesivas\n takeUntilDestroyed(this._destroyRef),\n )\n .subscribe({\n next: (): void => {\n this._zone.run((): void => {\n setTimeout((): void => {\n this.inputText?.nativeElement?.focus();\n // Forzar la apertura del panel y una posible carga si es necesario\n // Simular input para disparar valueChanges, lo que a menudo abre el panel si el texto cambia\n (\n this.inputText?.nativeElement as HTMLInputElement\n )?.dispatchEvent(new Event(\"input\"));\n // Abrir explícitamente el panel usando el MatAutocompleteTrigger\n this.autocompleteTrigger?.openPanel(); // <--- EL CAMBIO ES AQUÍ\n }, 50); // Un pequeño retraso para asegurar el foco y la apertura\n });\n },\n });\n }\n\n @Input() set notAllowedElements(element: any) {\n if (element) {\n this.notAllowedOption.set(element);\n this.filterOptionsBasedOnNotAllowed();\n }\n }\n\n /**\n * Resets the autocomplete pagination and options state.\n * Centralizes the logic to avoid duplication.\n */\n private resetAutocompleteState(): void {\n this._offset = 0;\n this.originalOptions.set([]);\n this.filteredOptions.set([]);\n this.hasMore.set(true);\n // IMPORTANTE: _selectedElement NO se resetea aquí, solo si se borra explícitamente\n // _lastSearchText se actualiza en writeValue y optionSelected\n console.log(\"Autocomplete state reset (pagination/options).\");\n }\n\n /**\n * Subscription to search input changes\n */\n private subscribeToComponentChanges(): void {\n this.component.valueChanges\n .pipe(\n // Utiliza tap para observar el valor antes del debounce y el switchMap\n tap((value) => {\n // Si el cambio viene de una selección programática (e.g., this.component.setValue(obj))\n // O de una selección del usuario en el autocomplete, marcamos que no necesitamos buscar.\n if (\n typeof value === \"object\" &&\n value !== null &&\n this._isOptionSelected\n ) {\n console.log(\n \"Value change detected: Object selected, skipping search.\",\n );\n // Resetear la bandera después de procesar\n this._isOptionSelected = false;\n return; // Salir del tap, el debounce/switchMap no se ejecutará para este valor.\n }\n }),\n debounceTime(this.debounceTimeValue),\n takeUntilDestroyed(this._destroyRef),\n )\n .subscribe({\n next: (value: any): void => {\n const currentSearchText = this.getAutocompleteSearchText();\n\n // Si el valor actual es un objeto (ya seleccionado), no necesitamos buscar\n // A menos que el texto en el input haya sido modificado por el usuario\n if (typeof value === \"object\" && value !== null) {\n const displayText = this.displayFn(value);\n if (\n currentSearchText === displayText &&\n this._selectedElement === value\n ) {\n console.log(\n \"Value is selected object and matches display text, skipping search.\",\n );\n return;\n }\n }\n\n // Si el valor del input es un string (el usuario está escribiendo o borró)\n // Y el texto actual es diferente al último texto buscado\n // O si el texto está vacío (para cargar las opciones iniciales si se borra)\n if (\n (typeof value === \"string\" &&\n currentSearchText !== this._lastSearchText) ||\n (currentSearchText === \"\" && this._lastSearchText !== \"\") // Para cuando el usuario borra todo\n ) {\n this.resetAutocompleteState(); // Reiniciar paginación y opciones\n this._lastSearchText = currentSearchText; // Actualizar el último texto buscado\n console.log(\n \"Value changed, initiating new search for:\",\n currentSearchText,\n );\n this.getAutocompleteByTextHandler(currentSearchText);\n } else if (currentSearchText === \"\" && this._lastSearchText === \"\") {\n // Si el input está vacío y ya lo estaba, y el componente no tiene valor seleccionado,\n // podría ser un buen momento para recargar las opciones iniciales si el panel está abierto\n if (\n this.matAutocomplete._isOpen &&\n this.originalOptions().length === 0 &&\n !this.loading()\n ) {\n console.log(\n \"Input empty, no options, panel open. Loading initial set.\",\n );\n this.getAutocompleteByTextHandler(\"\");\n }\n }\n },\n });\n }\n\n ngAfterViewInit(): void {\n // Suscribirse a la apertura del panel para añadir el listener de scroll\n this.matAutocomplete.opened\n .pipe(takeUntilDestroyed(this._destroyRef))\n .subscribe(() => {\n if (this.matAutocomplete?.panel) {\n // Asegurarse de que el listener sea removido antes de añadirlo para prevenir duplicados\n this.matAutocomplete.panel.nativeElement.removeEventListener(\n \"scroll\",\n this.onScroll.bind(this),\n );\n this.matAutocomplete.panel.nativeElement.addEventListener(\n \"scroll\",\n this.onScroll.bind(this),\n );\n\n // Si el panel se abre y no hay opciones cargadas, o si el input está vacío\n // y no hay una selección activa, cargar las opciones iniciales.\n const currentSearchText = this.getAutocompleteSearchText();\n if (\n this.originalOptions().length === 0 ||\n (!this._selectedElement && currentSearchText === \"\")\n ) {\n console.log(\"Panel opened, loading initial set of options.\");\n this.getAutocompleteByTextHandler(currentSearchText);\n }\n }\n });\n\n // Suscribirse al cierre del panel para remover el listener de scroll y manejar la deselección\n this.matAutocomplete.closed\n .pipe(takeUntilDestroyed(this._destroyRef))\n .subscribe(() => {\n if (this.matAutocomplete?.panel) {\n this.matAutocomplete.panel.nativeElement.removeEventListener(\n \"scroll\",\n this.onScroll.bind(this),\n );\n }\n\n const currentInputValue = this.component.value;\n const currentInputText = this.getAutocompleteSearchText();\n\n console.log(\n \"Autocomplete closed. Current Input Value:\",\n currentInputValue,\n \"Selected Element:\",\n this._selectedElement,\n \"Current Input Text:\",\n currentInputText,\n );\n\n // Lógica para manejar el borrado del input si no hay una selección válida\n // o si el texto no coincide con el elemento seleccionado.\n if (typeof currentInputValue === \"string\") {\n // Si el valor del input es un string (el usuario está escribiendo o ha modificado)\n if (this.requireSelection) {\n // Si se requiere selección y el texto no coincide con un elemento seleccionado,\n // o no hay ningún elemento seleccionado, entonces se borra.\n if (\n !this._selectedElement ||\n currentInputText !== this.displayFn(this._selectedElement)\n ) {\n console.warn(\n \"Autocomplete closed: Input cleared because selection is required and no valid match found.\",\n );\n this.clearInternalState(); // Usa un método para limpiar\n }\n } else {\n // Si NO se requiere selección, pero el usuario ha editado el texto de un elemento previamente seleccionado.\n // En este caso, NO borramos, sino que revertimos al texto del elemento seleccionado si existe.\n if (\n this._selectedElement &&\n currentInputText !== this.displayFn(this._selectedElement)\n ) {\n console.log(\n \"Autocomplete closed: Text edited for a selected item, reverting to original.\",\n );\n // Revertir al texto del elemento seleccionado.\n this.component.setValue(this._selectedElement, {\n emitEvent: false,\n });\n this._lastSearchText = this.displayFn(this._selectedElement);\n this.propagateChange(this._selectedElement); // Propagar el valor original si se revierte\n } else if (currentInputText === \"\" && this._selectedElement) {\n // Si el input está vacío pero había un elemento seleccionado, deseleccionar\n console.log(\n \"Autocomplete closed: Input cleared by user, deselecting element.\",\n );\n this.clearInternalState();\n } else if (currentInputText === \"\" && !this._selectedElement) {\n // Si el input está vacío y no había selección, simplemente asegúrate de que el estado interno refleje esto.\n console.log(\"Autocomplete closed: Input empty, no selection.\");\n this.clearInternalState(); // Asegura el estado\n }\n // Si el texto del input es un string y no se requiere selección,\n // y no hay _selectedElement, asumimos que el usuario quiere el texto libre.\n // No hacemos nada, el texto permanece.\n if (\n typeof currentInputValue === \"string\" &&\n !this.requireSelection &&\n !this._selectedElement\n ) {\n // Si no hay un elemento seleccionado pero el usuario escribió algo\n // y no se requiere selección, dejamos el texto tal cual.\n // Aseguramos que _lastSearchText se actualice para evitar re-búsquedas innecesarias.\n this._lastSearchText = currentInputText;\n this.propagateChange(currentInputText);\n }\n }\n }\n // Si el valor ya es un objeto (porque se seleccionó), no hacemos nada aquí\n // a menos que el usuario haya borrado manualmente el texto del input.\n // Esa última parte se cubre con la condición currentInputText === \"\"\n });\n }\n\n /**\n * Helper method to clear the internal state of the autocomplete.\n */\n private clearInternalState(): void {\n this.component.setValue(null, { emitEvent: false }); // Evitar bucle con valueChanges\n this.propagateChange(null);\n this.selectElement.emit(null);\n this._selectedElement = null;\n this._lastSearchText = \"\";\n this.resetAutocompleteState(); // Resetear opciones y paginación\n console.log(\"Internal autocomplete state cleared.\");\n }\n\n /**\n * Searches for elements to display in the autocomplete component.\n * Now supports pagination.\n * @param text - Text to search\n */\n private getAutocompleteByTextHandler(text?: string): void {\n // Si no hay más datos Y ya cargamos algo (offset > 0) Y el texto de búsqueda no ha cambiado,\n // y no estamos actualmente cargando, salir.\n if (\n !this.hasMore() &&\n this._offset > 0 &&\n text === this._lastSearchText && // Verificar que el texto de búsqueda actual sea el mismo\n !this.loading()\n ) {\n console.log(\n \"No more data for current search text, stopping further loads.\",\n );\n return;\n }\n\n if (this.loading()) {\n console.log(\"Already loading, exiting getAutocompleteByTextHandler.\");\n return;\n }\n\n this.loading.set(true);\n\n const currentOffset = this._offset; // Capturar el offset actual antes de la llamada\n const currentSearchTextForApi = text; // Usar el texto pasado, no el global _lastSearchText\n\n if (!this._url && !this.serviceConfig) {\n console.warn(\"Autocomplete: 'url' or 'serviceConfig' input is required.\");\n this.loading.set(false);\n this.hasMore.set(false);\n return;\n }\n\n let apiCall: Observable<any>;\n\n if (this._url) {\n apiCall = from(\n this._autocompleteService.getAutocompleteByText(\n this._url,\n currentSearchTextForApi, // Usar el texto de búsqueda actual\n this.filterString,\n this._restrictionsFilters,\n this.removeProperties,\n this.order,\n this.bodyRequest,\n { limit: this._limit, offset: currentOffset },\n ),\n ).pipe(switchMap((innerObservable) => innerObservable));\n } else if (this.serviceConfig) {\n let body: any = { ...this.serviceConfig };\n body[this.serviceConfig.searchProperty] = currentSearchTextForApi; // Usar el texto de búsqueda actual\n body[\"limit\"] = this._limit;\n body[\"offset\"] = currentOffset;\n apiCall = this.serviceConfig.service[this.serviceConfig.method](body);\n } else {\n this.loading.set(false);\n this.hasMore.set(false);\n return;\n }\n\n // Guardar la posición de scroll antes de la actualización\n let panelScrollTop = 0;\n if (this.matAutocomplete?.panel) {\n panelScrollTop = this.matAutocomplete.panel.nativeElement.scrollTop;\n }\n\n apiCall\n .pipe(\n finalize((): void => {\n this.loading.set(false);\n }),\n takeUntilDestroyed(this._destroyRef),\n )\n .subscribe({\n next: (result: any): void => {\n const newData = result?.payload?.data ?? result?.data ?? [];\n console.log(\n \"New Data received:\",\n newData.length,\n \"items. Current offset before update:\",\n this._offset,\n );\n\n this._offset += newData.length; // Actualizar offset con la cantidad de nuevos ítems\n\n if (newData.length < this._limit) {\n this.hasMore.set(false);\n console.log(\"No more data, hasMore = false\");\n } else {\n this.hasMore.set(true);\n console.log(\"Potentially more data, hasMore = true\");\n }\n\n // Actualizar las opciones originales\n this.originalOptions.update((currentOptions) => {\n const updatedOptions = [...currentOptions, ...newData];\n console.log(\"Total options after merge:\", updatedOptions.length);\n return updatedOptions;\n });\n this.filterOptionsBasedOnNotAllowed();\n\n // Restaurar la posición de scroll después de que Angular haya actualizado el DOM\n // Esto debe hacerse fuera de la zona de Angular o con un pequeño retardo.\n if (this.matAutocomplete?.panel && panelScrollTop > 0) {\n this._zone.runOutsideAngular(() => {\n setTimeout(() => {\n this.matAutocomplete.panel.nativeElement.scrollTop =\n panelScrollTop;\n console.log(\"Scroll position restored to:\", panelScrollTop);\n }, 0); // Un pequeño retardo para asegurar que el DOM se haya renderizado\n });\n }\n },\n error: (error) => {\n console.error(\"Error fetching autocomplete data:\", error);\n this.loading.set(false);\n this.hasMore.set(false);\n },\n });\n }\n\n private filterOptionsBasedOnNotAllowed(): void {\n let currentOptions = this.originalOptions();\n const modifiedOptions = this.modifyResultFn(currentOptions);\n if (modifiedOptions !== null && modifiedOptions !== undefined) {\n currentOptions = modifiedOptions;\n }\n\n if (this.notAllowedOption()) {\n this.filteredOptions.set(\n currentOptions.filter(\n (option: any): boolean =>\n JSON.stringify(option) !== JSON.stringify(this.notAllowedOption()),\n ),\n );\n } else {\n this.filteredOptions.set(currentOptions);\n }\n }\n\n /**\n * Defines the text to be used for the search\n */\n private getAutocompleteSearchText(): string {\n const value = this.component.value;\n if (typeof value === \"object\" && value !== null) {\n // Si el valor es un objeto, usa displayFn para obtener el texto\n return this.displayFn(value);\n } else if (typeof value === \"string\") {\n return value;\n }\n return \"\";\n }\n\n // --- ControlValueAccessor methods ---\n propagateChange = (_: any): void => {};\n\n registerOnChange(fn: (_: any) => void): void {\n this.propagateChange = fn;\n }\n\n registerOnTouched(): void {}\n\n /**\n * Recibe el valor desde el FormControl externo.\n */\n writeValue(value: any): void {\n // Establecer la bandera para indicar que el cambio viene de un setValue programático\n this._isOptionSelected = typeof value === \"object\" && value !== null;\n this.component.setValue(value, { emitEvent: false }); // No emitir evento para evitar bucles.\n\n this._selectedElement = value\n ? this.valueId && typeof value === \"object\"\n ? value?.id\n : value\n : null;\n\n // Actualizar _lastSearchText basado en el valor que se está escribiendo.\n if (value) {\n this._lastSearchText = this.displayFn(value);\n console.log(\"writeValue: Last search text set to:\", this._lastSearchText);\n } else {\n this._lastSearchText = \"\";\n console.log(\"writeValue: Last search text cleared.\");\n }\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.disabled.set(isDisabled);\n if (isDisabled) {\n this.component.disable();\n } else {\n this.component.enable();\n }\n }\n\n /**\n * Function to display selected elements\n */\n public displayFn = (value: any): string => {\n if (!value) {\n return \"\";\n }\n // Si el valor ya es una cadena, devuélvelo directamente\n if (typeof value === \"string\") {\n return value;\n }\n\n let displayText: string = \"\";\n const options = this.displayOptions || GENERAL_DISPLAY_OPTIONS;\n\n options?.firthLabel?.forEach((field: any): void => {\n if (field?.type === DisplayOptionItemType.PATH) {\n displayText +=\n UtilsService.resolvePropertyByPath(value, field?.path) || \"\";\n } else {\n displayText += field?.divider || \"\";\n }\n });\n\n return displayText;\n };\n\n /**\n * Action on clearing the input value\n */\n public clear(trigger: MatAutocompleteTrigger): void {\n this.clearElement.emit(this.component.value);\n this.clearInternalState(); // Usa el método auxiliar para limpiar\n // this.component.setValue(null); // Ya se llama dentro de clearInternalState\n // this.propagateChange(null);\n // this.selectElement.emit(null);\n // this._selectedElement = null;\n // this._lastSearchText = \"\";\n\n this._zone.run((): void => {\n setTimeout((): void => {\n trigger.openPanel(); // Reabrir el panel después de borrar\n this.getAutocompleteByTextHandler(\"\"); // Cargar opciones iniciales (o todas) después de borrar\n }, 100);\n });\n }\n\n /**\n * Action on element Focus\n */\n public onFocus(): void {\n const currentSearchText = this.getAutocompleteSearchText();\n // Si no hay opciones cargadas O el input está vacío y no hay un elemento seleccionado\n if (\n this.originalOptions().length === 0 ||\n (currentSearchText === \"\" && !this._selectedElement)\n ) {\n this.resetAutocompleteState(); // Reiniciar estado antes de una nueva búsqueda\n this._lastSearchText = currentSearchText;\n console.log(\"On focus, initiating search for:\", currentSearchText);\n this.getAutocompleteByTextHandler(currentSearchText);\n } else if (\n this.matAutocomplete._isOpen &&\n currentSearchText === this._lastSearchText\n ) {\n // Si el panel ya está abierto y el texto no ha cambiado, no hacer nada para evitar re-cargas innecesarias.\n // Si el panel no estaba abierto, la apertura de `matAutocomplete.opened` se encargará de la carga.\n console.log(\n \"On focus, panel already open with same text, skipping search.\",\n );\n }\n }\n\n public optionSelected($event: any): void {\n const selectedValue = $event?.option?.value;\n if (selectedValue) {\n this._isOptionSelected = true; // Establecer la bandera de selección\n this._selectedElement = selectedValue;\n this.selectElement.emit(selectedValue);\n\n if (this.valueId && typeof selectedValue === \"object\") {\n this.propagateChange(selectedValue?.id);\n } else {\n this.propagateChange(selectedValue);\n }\n // Cuando un ítem es seleccionado, actualizar _lastSearchText con su valor de display.\n // Esto es crucial para que el valueChanges no vuelva a disparar una búsqueda para este valor.\n this._lastSearchText = this.displayFn(selectedValue);\n console.log(\n \"Option selected. Last search text set to:\",\n this._lastSearchText,\n );\n } else {\n // Si se deselecciona o selecciona nulo\n // Esto rara vez debería ocurrir si se selecciona una opción válida, pero es un fallback.\n console.log(\"Option selected is null or undefined, clearing state.\");\n this.clearInternalState();\n }\n // Después de la selección, el panel se cierra automáticamente en la mayoría de los casos de MatAutocomplete.\n // this.matAutocomplete.closePanel(); // Descomentar si el panel no se cierra automáticamente\n }\n\n /**\n * Handles the scroll event in the autocomplete panel to load more data.\n */\n onScroll(event: Event): void {\n const element = event.target as HTMLElement;\n const scrollPosition = element.scrollTop + element.clientHeight;\n const scrollHeight = element.scrollHeight;\n const threshold = 50; // Pixels before the end to load more\n\n // console.log(\"--- Scroll Event ---\");\n // console.log(\"Scroll Top:\", element.scrollTop);\n // console.log(\"Client Height:\", element.clientHeight);\n // console.log(\"Scroll Position (Top + Client):\", scrollPosition);\n // console.log(\"Scroll Height (Total):\", scrollHeight);\n // console.log(\"Remaining distance to bottom:\", scrollHeight - scrollPosition);\n // console.log(\"Is Loading:\", this.loading());\n // console.log(\"Has More:\", this.hasMore());\n\n if (\n scrollHeight - scrollPosition <= threshold &&\n !this.loading() &&\n this.hasMore()\n ) {\n console.log(\"Loading more data for infinity scroll...\");\n // Usar el texto de búsqueda actual (que puede ser el texto del ítem seleccionado o lo que el usuario escribió)\n this.getAutocompleteByTextHandler(this.getAutocompleteSearchText());\n }\n }\n}\n\n/**\n * Custom validation for element selection\n */\nexport function autocompleteValidator(\n control: AbstractControl,\n): ValidationErrors | null {\n // Un valor válido es un objeto no nulo que tiene una propiedad 'id'.\n // Esto asegura que realmente se ha seleccionado un objeto del autocomplete, no solo texto libre.\n if (\n typeof control?.value === \"object\" &&\n control?.value !== null &&\n \"id\" in control.value\n ) {\n return null;\n }\n return { invalidSelection: true };\n}\n","<mat-form-field [floatLabel]=\"floatLabel\" class=\"w-100\" [appearance]=\"appearance\" [color]=\"color\"\n [subscriptSizing]=\"subscriptSizing\">\n\n @if (showLabel) {\n <mat-label>{{ label | translate }}</mat-label>\n }\n @if (showSuffix) {\n <mat-icon matSuffix>{{ suffixIcon ?? \"search\" }}</mat-icon>\n }\n <input #inputText #trigger=\"matAutocompleteTrigger\" (focus)=\"onFocus()\" [formControl]=\"component\" type=\"text\"\n [matAutocomplete]=\"auto\" [placeholder]=\"placeholder | translate\" aria-label=\"autocomplete\"\n autocomplete=\"off\" matInput [required]=\"required()\">\n @if (!loading() && component.value) {\n <button (click)=\"clear(trigger)\" [disabled]=\"disabled()\"\n aria-label=\"Clear\" mat-icon-button matSuffix>\n <mat-icon>close</mat-icon>\n </button>\n }\n @if (loading()) {\n <button aria-label=\"search\" mat-icon-button matSuffix>\n <mat-spinner [value]=\"90\" color=\"accent\" diameter=\"25\"></mat-spinner>\n </button>\n }\n <mat-autocomplete #auto=\"matAutocomplete\" [displayWith]=\"displayFn\" [requireSelection]=\"requireSelection\"\n (optionSelected)=\"optionSelected($event)\">\n @for (option of filteredOptions(); track option) {\n <mat-option [value]=\"option\">\n @if (!displayOptions && !detailsTemplate) {\n {{ option?.name | i18n: translateService.currentLang }}\n }\n @if (!detailsTemplate) {\n <div class=\"display-options\">\n <span [ngStyle]=\"{'line-height': displayOptions?.secondLabel ? '16px' : ''}\">\n {{ option | resolvePropertyPath:displayOptions.firthLabel | i18n: translateService.currentLang }}\n </span>\n @if (displayOptions?.secondLabel) {\n <span class=\"mat-caption\">\n {{ option | resolvePropertyPath: displayOptions.secondLabel | i18n: translateService.currentLang }}\n </span>\n }\n </div>\n }\n @if (detailsTemplate) {\n <ng-container *ngTemplateOutlet=\"detailsTemplate;context:{$implicit: option }\"></ng-container>\n }\n </mat-option>\n }\n </mat-autocomplete>\n\n @if (component.invalid) {\n <mat-error>\n {{ 'Este campo es requerido.' | translate }}\n </mat-error>\n }\n</mat-form-field>\n","/*\n * Public API Surface of guachos-general-autocomplete\n */\n\nexport * from './utils/constants/constants';\nexport * from './lib/guachos-general-autocomplete.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
1
|
+
{"version":3,"file":"guajiritos-general-autocomplete.mjs","sources":["../../../projects/guachos-general-autocomplete/src/utils/constants/constants.ts","../../../projects/guachos-general-autocomplete/src/utils/services/utils.service.ts","../../../projects/guachos-general-autocomplete/src/utils/pipes/resolve-property-path.pipe.ts","../../../projects/guachos-general-autocomplete/src/lib/guachos-general-autocomplete.component.ts","../../../projects/guachos-general-autocomplete/src/lib/guachos-general-autocomplete.component.html","../../../projects/guachos-general-autocomplete/src/public-api.ts","../../../projects/guachos-general-autocomplete/src/guajiritos-general-autocomplete.ts"],"sourcesContent":["import { DisplayOption, DisplayOptionItemType } from '@guajiritos/services';\nimport {DisplayOptionItem} from \"@guajiritos/services/lib/interfaces/interfaces\";\n\n\nexport const GENERAL_DISPLAY_OPTIONS: DisplayOption = {\n firthLabel: [\n {\n type: DisplayOptionItemType.PATH,\n path: ['name']\n }\n ],\n applyTranslate: true\n};\n\nexport interface ServiceConfig {\n service: any;\n method: string;\n postBody: any;\n searchProperty: string;\n}\n","import {Injectable} from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class UtilsService {\n /**\n * Resolves the value of a property in an object by providing a path.\n *\n * @param {any} obj - The object to traverse.\n * @param {string[]} path - An array of strings representing the path to the desired property.\n * @return {any} The value of the property at the given path, or null if the path is invalid.\n */\n public static resolvePropertyByPath(obj: any, path: string[]): any {\n return path.reduce((prev, curr: string) => {\n return prev ? prev[curr] : null;\n }, obj || self);\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\nimport { DisplayOptionItem, DisplayOptionItemType } from '@guajiritos/services';\n\nimport { UtilsService } from '../services/utils.service';\n\n@Pipe({\n name: 'resolvePropertyPath',\n standalone: true\n})\nexport class ResolvePropertyPath implements PipeTransform {\n /**\n * Transforms the given object based on the provided path and returns the transformed string.\n *\n * @param {any} obj - The object to be transformed.\n * @param {DisplayOptionItem[]} path - The array of display option items used for transformation.\n * @return {string} The transformed string.\n */\n transform(obj: any, path: DisplayOptionItem[]): string {\n let result: string = '';\n\n path?.forEach((item: DisplayOptionItem): void => {\n if (item?.type === DisplayOptionItemType.DIVIDER) {\n result += item?.divider;\n } else {\n if (item?.path) {\n result += UtilsService.resolvePropertyByPath(obj, item.path);\n }\n }\n });\n\n return result;\n }\n}\n","import { CommonModule } from \"@angular/common\";\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n EventEmitter,\n forwardRef,\n Input,\n NgZone,\n Output,\n signal,\n TemplateRef,\n ViewChild,\n WritableSignal,\n} from \"@angular/core\";\nimport {\n AbstractControl,\n ControlValueAccessor,\n NG_VALUE_ACCESSOR,\n ReactiveFormsModule,\n UntypedFormControl,\n ValidationErrors,\n ValidatorFn,\n Validators,\n} from \"@angular/forms\";\nimport {\n MatAutocomplete,\n MatAutocompleteModule,\n MatAutocompleteTrigger,\n} from \"@angular/material/autocomplete\";\nimport { MatButtonModule } from \"@angular/material/button\";\nimport { ThemePalette } from \"@angular/material/core\";\nimport {\n FloatLabelType,\n MatFormFieldAppearance,\n MatFormFieldModule,\n SubscriptSizing,\n} from \"@angular/material/form-field\";\nimport { MatIconModule } from \"@angular/material/icon\";\nimport { MatInputModule } from \"@angular/material/input\";\nimport { MatProgressSpinnerModule } from \"@angular/material/progress-spinner\";\nimport { TranslateModule, TranslateService } from \"@ngx-translate/core\";\nimport {\n debounceTime,\n finalize,\n Observable,\n Subject,\n from,\n switchMap,\n tap,\n} from \"rxjs\";\nimport { takeUntilDestroyed } from \"@angular/core/rxjs-interop\";\n\nimport {\n ApiFormData,\n AutocompleteService,\n DisplayOption,\n DisplayOptionItemType,\n I18nPipe,\n RestrictionFilter,\n} from \"@guajiritos/services\";\n\nimport {\n GENERAL_DISPLAY_OPTIONS,\n ServiceConfig,\n} from \"../utils/constants/constants\";\nimport { ResolvePropertyPath } from \"../utils/pipes/resolve-property-path.pipe\";\nimport { UtilsService } from \"../utils/services/utils.service\";\n\n@Component({\n selector: \"guajiritos-general-autocomplete\",\n templateUrl: \"./guachos-general-autocomplete.component.html\",\n styleUrls: [\"./guachos-general-autocomplete.component.scss\"],\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n imports: [\n CommonModule,\n MatFormFieldModule,\n TranslateModule,\n MatIconModule,\n ReactiveFormsModule,\n MatInputModule,\n MatButtonModule,\n MatProgressSpinnerModule,\n MatAutocompleteModule,\n I18nPipe,\n ResolvePropertyPath,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => GuajiritosGeneralAutocomplete),\n multi: true,\n },\n ],\n})\nexport class GuajiritosGeneralAutocomplete\n implements ControlValueAccessor, AfterViewInit\n{\n constructor(\n private _autocompleteService: AutocompleteService,\n private _zone: NgZone,\n private _destroyRef: DestroyRef,\n public translateService: TranslateService,\n ) {}\n\n // --- Propiedades Privadas ---\n private _isOptionSelected: boolean = false; // Indica si la última actualización del input fue por una selección explícita desde el autocompletado\n private _clearDataSubject: Subject<void> = new Subject<void>();\n private _doFocusSubject: Subject<void> = new Subject<void>();\n private _selectedElement: any = null; // Almacena el objeto completo seleccionado\n private _url: string | null = null;\n private _limit: number = 20;\n private _offset: number = 0;\n private _restrictionsFilters: RestrictionFilter[] = [];\n private _lastSearchText: string = \"\"; // Almacena el texto usado en la última búsqueda de API exitosa\n\n // --- Señales Públicas (Signals) ---\n public disabled: WritableSignal<boolean> = signal(false);\n public loading: WritableSignal<boolean> = signal(false);\n public required: WritableSignal<boolean> = signal(false);\n public filteredOptions: WritableSignal<any[]> = signal([]);\n public originalOptions: WritableSignal<any[]> = signal([]);\n public notAllowedOption: WritableSignal<any> = signal(null);\n public component: UntypedFormControl = new UntypedFormControl({\n value: null,\n disabled: false,\n });\n public hasMore: WritableSignal<boolean> = signal(true); // Indica si hay más datos para cargar\n\n // --- ViewChildren ---\n @ViewChild(\"inputText\", { static: true }) inputText!: ElementRef;\n @ViewChild(\"auto\") matAutocomplete!: MatAutocomplete;\n @ViewChild(MatAutocompleteTrigger)\n autocompleteTrigger!: MatAutocompleteTrigger;\n\n // --- Inputs ---\n @Input() floatLabel: FloatLabelType = \"auto\";\n @Input() color: ThemePalette = \"accent\";\n @Input() appearance: MatFormFieldAppearance = \"outline\";\n @Input() subscriptSizing: SubscriptSizing = \"dynamic\";\n @Input() bodyRequest?: ApiFormData;\n @Input() debounceTimeValue: number = 300;\n @Input() detailsTemplate?: TemplateRef<any>;\n @Input() label: string = \"Seleccione\";\n @Input() showLabel: boolean = true;\n @Input() placeholder: string = \"Seleccione un elemento\";\n @Input() field: string[] = [\"name\"];\n @Input() filterString: string[] | string = \"filter[$and][name][$like]\";\n @Input() displayOptions: DisplayOption = GENERAL_DISPLAY_OPTIONS;\n @Input() withoutPaddingBottom: boolean = true;\n @Input() valueId: boolean = false;\n @Input() showSuffix: boolean = false;\n @Input() requireSelection: boolean = false;\n @Input() order?: string;\n @Input() serviceConfig?: ServiceConfig;\n @Input() suffixIcon: string = \"search\";\n @Input() removeProperties: string[] = [];\n @Input() modifyResultFn: (options: any[]) => any[] = (options: any[]) =>\n options;\n\n // --- Outputs ---\n @Output() selectElement: EventEmitter<any> = new EventEmitter<any>();\n @Output() clearElement: EventEmitter<any> = new EventEmitter<any>();\n\n // --- Setters para Inputs ---\n @Input() set url(data: string) {\n if (data) {\n this._url = data;\n // Suscribirse a los cambios del componente una vez que la URL está disponible\n this.subscribeToComponentChanges();\n }\n }\n\n @Input() set limit(value: number) {\n if (value && !isNaN(value)) {\n this._limit = value;\n }\n }\n\n @Input() set clearData(value: Subject<void>) {\n this._clearDataSubject = value;\n this._clearDataSubject\n .pipe(takeUntilDestroyed(this._destroyRef))\n .subscribe({\n next: (): void => {\n this.clearInternalState();\n },\n });\n }\n\n @Input() set initialValue(value: any) {\n // Si el valor inicial es el mismo que el valor actual del control, no hacer nada para evitar bucles\n if (value === this.component.value) {\n return;\n }\n\n this._selectedElement = value;\n this._isOptionSelected = !!value; // Marcar como seleccionado si hay un valor inicial\n\n // Establecer el valor en el formControl sin emitir el evento\n // para evitar que subscribeToComponentChanges reaccione a esta carga inicial.\n this.component.setValue(value, { emitEvent: false });\n\n // Actualizar _lastSearchText basado en el valor inicial\n if (value) {\n this._lastSearchText = this.displayFn(value);\n console.log(\n \"initialValue establecido: _lastSearchText =\",\n this._lastSearchText,\n );\n } else {\n this._lastSearchText = \"\";\n }\n }\n\n /**\n * Añade o elimina restricciones de búsqueda\n */\n @Input() set restrictions(restrictions: RestrictionFilter[]) {\n this._restrictionsFilters = restrictions?.length ? [...restrictions] : [];\n // Siempre resetear el estado cuando cambian las restricciones\n this.resetAutocompleteState();\n // Re-ejecutar búsqueda si el input tiene texto o si está vacío y no hay selección, o si las restricciones cambiaron realmente el resultado esperado.\n const currentSearchText = this.getAutocompleteSearchText();\n // Sólo si ya había un texto o una selección, o si las restricciones realmente impactan la búsqueda inicial.\n if (\n currentSearchText !== this._lastSearchText ||\n (!currentSearchText && !this._selectedElement) ||\n restrictions?.length > 0\n ) {\n console.log(\"Restricciones cambiadas, iniciando nueva búsqueda.\");\n // No actualizar _lastSearchText aquí, se actualiza después de la API.\n this.getAutocompleteByTextHandler(currentSearchText);\n }\n }\n\n /**\n * Añade o elimina la validación de requerido\n */\n @Input() set isRequired(required: boolean) {\n this.required.set(required);\n const validators: ValidatorFn[] = [autocompleteValidator];\n if (required) {\n validators.push(Validators.required);\n }\n this.component.setValidators(validators);\n this.component.updateValueAndValidity();\n }\n\n /**\n * Define si se realiza una búsqueda cuando el elemento está en foco\n */\n @Input() set doFocus(focusSubject: Subject<void>) {\n this._doFocusSubject = focusSubject;\n this._doFocusSubject\n .pipe(\n debounceTime(this.debounceTimeValue), // Retrasar para evitar llamadas excesivas\n takeUntilDestroyed(this._destroyRef),\n )\n .subscribe({\n next: (): void => {\n this._zone.run((): void => {\n setTimeout((): void => {\n this.inputText?.nativeElement?.focus();\n // Simular evento 'input' para disparar valueChanges, pero solo si el input está vacío\n // o si ya hay un valor pero no es el seleccionado (usuario queriendo buscar de nuevo).\n if (\n !this.component.value ||\n (typeof this.component.value === \"string\" &&\n !this._selectedElement)\n ) {\n (\n this.inputText?.nativeElement as HTMLInputElement\n )?.dispatchEvent(new Event(\"input\"));\n }\n this.autocompleteTrigger?.openPanel();\n }, 50); // Un pequeño retraso para asegurar el foco y la apertura\n });\n },\n });\n }\n\n @Input() set notAllowedElements(element: any) {\n if (element) {\n this.notAllowedOption.set(element);\n this.filterOptionsBasedOnNotAllowed();\n }\n }\n\n /**\n * Reinicia el estado de paginación y opciones del autocompletado.\n * Centraliza la lógica para evitar duplicación.\n */\n private resetAutocompleteState(): void {\n this._offset = 0;\n this.originalOptions.set([]);\n this.filteredOptions.set([]);\n this.hasMore.set(true);\n console.log(\"Estado de autocompletado reiniciado (paginación/opciones).\");\n }\n\n /**\n * Suscripción a los cambios del input de búsqueda\n */\n private subscribeToComponentChanges(): void {\n this.component.valueChanges\n .pipe(\n // TAP se ejecuta inmediatamente ANTES del debounce.\n // Esto es crucial para detectar borrados de texto en tiempo real y desvincular _selectedElement.\n tap((value) => {\n const currentInputText = this.getAutocompleteSearchText();\n\n // Si el valor actual del control es un STRING (usuario escribiendo/borrando)\n // Y previamente había un objeto seleccionado (_selectedElement)\n // Y el texto en el input ya no coincide con el displayFn del _selectedElement,\n // entonces desvinculamos el _selectedElement y marcamos que no hay selección.\n if (\n typeof value === \"string\" &&\n this._selectedElement &&\n currentInputText !== this.displayFn(this._selectedElement)\n ) {\n console.log(\n \"TAP: El usuario está editando/borrando texto de un elemento seleccionado. Deseleccionando internamente.\",\n );\n this._selectedElement = null; // Quitar la referencia al objeto seleccionado\n this._isOptionSelected = false; // Marcar que no hay una opción seleccionada\n } else if (typeof value === \"string\") {\n // Si el valor es un string, simplemente marcamos que no hay opción seleccionada.\n // Esto cubre los casos donde el usuario escribe por primera vez o borra sin haber seleccionado.\n this._isOptionSelected = false;\n }\n }),\n debounceTime(this.debounceTimeValue), // El debounce se aplica después de la lógica del tap\n takeUntilDestroyed(this._destroyRef),\n )\n .subscribe({\n next: (value: any): void => {\n const currentSearchText = this.getAutocompleteSearchText();\n\n // Caso 1: El valor es un objeto y coincide con el elemento seleccionado.\n // Esto ocurre si el usuario seleccionó un elemento y el debounce pasó sin más ediciones.\n if (\n typeof value === \"object\" &&\n value !== null &&\n this._selectedElement === value\n ) {\n console.log(\n \"El valor es un objeto seleccionado (después de debounce), saltando la búsqueda.\",\n );\n // Aseguramos que el _lastSearchText esté correcto para este objeto.\n this._lastSearchText = this.displayFn(value);\n return;\n }\n\n // Caso 2: El usuario ha terminado de escribir o borrar texto.\n // Si el texto actual ha cambiado con respecto al último buscado.\n if (currentSearchText !== this._lastSearchText) {\n this.resetAutocompleteState(); // Reiniciar paginación y opciones para la nueva búsqueda\n this._lastSearchText = currentSearchText; // Actualizar el último texto buscado ANTES de la llamada a la API\n console.log(\n \"El valor ha cambiado (después de debounce), iniciando nueva búsqueda para:\",\n currentSearchText,\n );\n this.getAutocompleteByTextHandler(currentSearchText);\n\n // Propagar el valor del input al control externo si no hay un elemento seleccionado\n // y el texto no está vacío, o si está vacío y no hay selección.\n if (!this._selectedElement && currentSearchText !== \"\") {\n this.propagateChange(currentSearchText);\n } else if (!this._selectedElement && currentSearchText === \"\") {\n this.propagateChange(null);\n }\n } else {\n console.log(\n \"El valor no ha cambiado o es un estado estable, saltando nueva búsqueda de valueChanges.\",\n );\n // Si el texto es el mismo, pero el panel está abierto, sin opciones y hay más datos potenciales,\n // podemos necesitar una recarga (ej. si una búsqueda anterior falló o la red fue lenta).\n if (\n this.matAutocomplete._isOpen &&\n this.originalOptions().length === 0 &&\n !this.loading() &&\n this.hasMore() &&\n currentSearchText === \"\" // Solo si el input está vacío y no hay opciones\n ) {\n console.log(\n \"Input sin cambios pero panel abierto/vacío, activando re-búsqueda.\",\n );\n this.getAutocompleteByTextHandler(currentSearchText);\n }\n }\n },\n });\n }\n\n ngAfterViewInit(): void {\n // Suscribirse a la apertura del panel para añadir el listener de scroll y cargar datos\n this.matAutocomplete.opened\n .pipe(takeUntilDestroyed(this._destroyRef))\n .subscribe(() => {\n if (this.matAutocomplete?.panel) {\n // Asegurarse de que el listener sea removido antes de añadirlo para prevenir duplicados\n this.matAutocomplete.panel.nativeElement.removeEventListener(\n \"scroll\",\n this.onScroll.bind(this),\n );\n this.matAutocomplete.panel.nativeElement.addEventListener(\n \"scroll\",\n this.onScroll.bind(this),\n );\n\n const currentSearchText = this.getAutocompleteSearchText();\n\n // **********************************************\n // MODIFICACIÓN CLAVE AQUÍ:\n // Cargar opciones iniciales SOLO SI:\n // 1. No hay opciones cargadas (primera apertura o después de un clear/reset).\n // 2. O el texto actual en el input es diferente del _lastSearchText (el usuario escribió algo nuevo o borró y abrió).\n // 3. O el input está vacío Y no hay un _selectedElement Y hay más datos por cargar Y el offset es 0 (lo que implica que es la primera carga para este estado vacío).\n // Esto evita la doble llamada si subscribeToComponentChanges ya disparó una búsqueda\n // para el mismo texto, o si ya se sabe que no hay más datos para un input vacío.\n // **********************************************\n if (\n this.originalOptions().length === 0 || // No hay opciones, cargar siempre.\n currentSearchText !== this._lastSearchText || // El texto ha cambiado, nueva búsqueda.\n (currentSearchText === \"\" &&\n !this._selectedElement &&\n this.hasMore() &&\n this._offset === 0) // Input vacío, sin selección, con potencial de datos, y es la primera carga.\n ) {\n console.log(\n \"Panel abierto, condiciones cumplidas para búsqueda inicial/nueva. Cargando conjunto inicial de opciones.\",\n );\n this.resetAutocompleteState(); // Asegurarse de resetear antes de una nueva carga\n this._lastSearchText = currentSearchText; // Sincronizar _lastSearchText con la búsqueda que se va a realizar\n this.getAutocompleteByTextHandler(currentSearchText);\n } else {\n console.log(\n \"Panel abierto, opciones ya cargadas o elemento seleccionado existe, o texto sin cambios. Saltando carga inicial.\",\n );\n }\n }\n });\n\n // Suscribirse al cierre del panel para remover el listener de scroll y manejar la deselección\n this.matAutocomplete.closed\n .pipe(takeUntilDestroyed(this._destroyRef))\n .subscribe(() => {\n if (this.matAutocomplete?.panel) {\n this.matAutocomplete.panel.nativeElement.removeEventListener(\n \"scroll\",\n this.onScroll.bind(this),\n );\n }\n\n const currentInputValue = this.component.value;\n const currentInputText = this.getAutocompleteSearchText();\n\n console.log(\n \"Autocompletado cerrado. Valor actual del Input:\",\n currentInputValue,\n \"Elemento seleccionado:\",\n this._selectedElement,\n \"Texto actual del Input:\",\n currentInputText,\n );\n\n // Lógica para manejar el borrado del input si no hay una selección válida\n // o si el texto no coincide con el elemento seleccionado.\n if (typeof currentInputValue === \"string\") {\n // Si el input está vacío Y no hay un elemento seleccionado\n if (currentInputText === \"\" && !this._selectedElement) {\n console.log(\n \"Autocompletado cerrado: Input vacío y sin selección. Limpiando estado interno.\",\n );\n this.clearInternalState(); // Usa un método para limpiar\n }\n // Si se requiere selección y el texto no coincide con el elemento seleccionado,\n // o no hay ningún elemento seleccionado, entonces se borra.\n else if (\n this.requireSelection &&\n (!this._selectedElement ||\n currentInputText !== this.displayFn(this._selectedElement))\n ) {\n console.warn(\n \"Autocompletado cerrado: Selección requerida y no se encontró una coincidencia válida. Limpiando input.\",\n );\n this.clearInternalState(); // Usa un método para limpiar\n }\n // Si NO se requiere selección, pero el usuario ha editado el texto de un elemento previamente seleccionado.\n // En este caso, NO borramos, sino que revertimos al texto del elemento seleccionado si existe.\n else if (\n this._selectedElement &&\n currentInputText !== this.displayFn(this._selectedElement) &&\n !this.requireSelection\n ) {\n console.log(\n \"Autocompletado cerrado: Texto editado para un elemento seleccionado, revirtiendo al original.\",\n );\n // Revertir al texto del elemento seleccionado.\n this.component.setValue(this._selectedElement, {\n emitEvent: false,\n });\n this._lastSearchText = this.displayFn(this._selectedElement);\n this.propagateChange(this._selectedElement); // Propagar el valor original si se revierte\n }\n // Si el texto del input es un string y no se requiere selección,\n // y no hay _selectedElement (porque se deseleccionó en el tap o nunca hubo),\n // asumimos que el usuario quiere el texto libre.\n // No hacemos nada, el texto permanece.\n else if (\n typeof currentInputValue === \"string\" &&\n !this.requireSelection &&\n !this._selectedElement &&\n currentInputText !== \"\"\n ) {\n // Si no hay un elemento seleccionado pero el usuario escribió algo\n // y no se requiere selección, dejamos el texto tal cual.\n // Aseguramos que _lastSearchText se actualice para evitar re-búsquedas innecesarias.\n this._lastSearchText = currentInputText;\n this.propagateChange(currentInputText);\n }\n }\n // Si el valor ya es un objeto (porque se seleccionó) pero el texto del input fue borrado\n // y el _selectedElement es null (ya se desvinculó en el tap), significa que debe limpiarse.\n else if (\n typeof currentInputValue === \"object\" &&\n currentInputText === \"\" &&\n !this._selectedElement\n ) {\n console.log(\n \"Autocompletado cerrado: Valor de objeto pero input limpiado por el usuario. Deseleccionando.\",\n );\n this.clearInternalState();\n }\n });\n }\n\n /**\n * Método auxiliar para limpiar el estado interno del autocompletado.\n * Este método ahora se encarga de la limpieza profunda, incluyendo el valor del FormControl y la propagación.\n * @param resetLastSearchText - Si es true, reinicia _lastSearchText a una cadena vacía. Por defecto es true.\n */\n private clearInternalState(resetLastSearchText: boolean = true): void {\n // Solo si el valor del control NO es null, lo seteamos a null para evitar bucles.\n // Esto es importante porque en el tap, solo desvinculamos `_selectedElement` pero no el control.\n if (this.component.value !== null) {\n this.component.setValue(null, { emitEvent: false });\n }\n this.propagateChange(null);\n this.selectElement.emit(null);\n this._selectedElement = null; // Asegurar que el objeto seleccionado esté a null\n this._isOptionSelected = false; // Asegurar que la bandera de selección esté a false\n if (resetLastSearchText) {\n this._lastSearchText = \"\";\n }\n this.resetAutocompleteState(); // Resetear opciones y paginación\n console.log(\"Estado interno del autocompletado limpiado.\");\n }\n\n /**\n * Busca elementos para mostrar en el componente de autocompletado.\n * Ahora soporta paginación.\n * @param text - Texto a buscar\n */\n private getAutocompleteByTextHandler(text?: string): void {\n const currentSearchText = text ?? \"\";\n\n // Si ya estamos cargando, salimos para evitar peticiones duplicadas.\n if (this.loading()) {\n console.log(\n \"Ya estamos cargando, saliendo de getAutocompleteByTextHandler.\",\n );\n return;\n }\n\n // **********************************************\n // CLAVE: Evitar búsquedas innecesarias cuando ya se sabe que no hay más datos\n // para el texto actual.\n // Importante: Esto no debe detener la primera carga (offset 0).\n // **********************************************\n if (\n !this.hasMore() && // No hay más datos\n this._offset > 0 && // Ya se cargó algo antes\n currentSearchText === this._lastSearchText // El mismo texto de búsqueda para el que ya se agotaron los resultados\n ) {\n console.log(\n \"No hay más datos para el texto de búsqueda actual, deteniendo cargas adicionales.\",\n );\n return;\n }\n\n this.loading.set(true);\n\n const currentOffset = this._offset; // Capturar el offset actual antes de la llamada\n\n if (!this._url && !this.serviceConfig) {\n console.warn(\n \"Autocompletado: Se requiere el input 'url' o 'serviceConfig'.\",\n );\n this.loading.set(false);\n this.hasMore.set(false);\n return;\n }\n\n let apiCall: Observable<any>;\n\n if (this._url) {\n apiCall = from(\n this._autocompleteService.getAutocompleteByText(\n this._url,\n currentSearchText, // Usar el texto de búsqueda actual\n this.filterString,\n this._restrictionsFilters,\n this.removeProperties,\n this.order,\n this.bodyRequest,\n { limit: this._limit, offset: currentOffset },\n ),\n ).pipe(switchMap((innerObservable) => innerObservable));\n } else if (this.serviceConfig) {\n let body: any = { ...this.serviceConfig };\n body[this.serviceConfig.searchProperty] = currentSearchText; // Usar el texto de búsqueda actual\n body[\"limit\"] = this._limit;\n body[\"offset\"] = currentOffset;\n apiCall = this.serviceConfig.service[this.serviceConfig.method](body);\n } else {\n this.loading.set(false);\n this.hasMore.set(false);\n return;\n }\n\n // Guardar la posición de scroll antes de la actualización\n let panelScrollTop = 0;\n if (this.matAutocomplete?.panel) {\n panelScrollTop = this.matAutocomplete.panel.nativeElement.scrollTop;\n }\n\n apiCall\n .pipe(\n finalize((): void => {\n this.loading.set(false);\n }),\n takeUntilDestroyed(this._destroyRef),\n )\n .subscribe({\n next: (result: any): void => {\n const newData = result?.payload?.data ?? result?.data ?? [];\n console.log(\n \"Nuevos datos recibidos:\",\n newData.length,\n \"elementos. Offset actual antes de la actualización:\",\n this._offset,\n );\n\n // Si el offset es 0 (primera carga para esta búsqueda), reemplazamos las opciones.\n // De lo contrario, las añadimos.\n // Esto maneja que cada nueva búsqueda reemplace los resultados anteriores,\n // y el scroll añada a los existentes.\n if (currentOffset === 0) {\n this.originalOptions.set(newData);\n console.log(\n \"Primera carga para este texto. Opciones originales reemplazadas.\",\n );\n } else {\n this.originalOptions.update((currentOptions) => [\n ...currentOptions,\n ...newData,\n ]);\n console.log(\n \"Carga adicional por scroll. Opciones originales actualizadas.\",\n );\n }\n\n this._offset += newData.length; // Actualizar offset con la cantidad de nuevos ítems\n\n if (newData.length < this._limit) {\n this.hasMore.set(false);\n console.log(\"No hay más datos, hasMore = false\");\n } else {\n this.hasMore.set(true);\n console.log(\"Potencialmente más datos, hasMore = true\");\n }\n\n this.filterOptionsBasedOnNotAllowed();\n\n // Restaurar la posición de scroll después de que Angular haya actualizado el DOM\n // Esto debe hacerse fuera de la zona de Angular o con un pequeño retardo.\n if (this.matAutocomplete?.panel && panelScrollTop > 0) {\n this._zone.runOutsideAngular(() => {\n setTimeout(() => {\n this.matAutocomplete.panel.nativeElement.scrollTop =\n panelScrollTop;\n console.log(\"Posición de scroll restaurada a:\", panelScrollTop);\n }, 0); // Un pequeño retardo para asegurar que el DOM se haya renderizado\n });\n }\n },\n error: (error) => {\n console.error(\"Error al obtener datos de autocompletado:\", error);\n this.loading.set(false);\n this.hasMore.set(false);\n },\n });\n }\n\n private filterOptionsBasedOnNotAllowed(): void {\n let currentOptions = this.originalOptions();\n const modifiedOptions = this.modifyResultFn(currentOptions);\n if (modifiedOptions !== null && modifiedOptions !== undefined) {\n currentOptions = modifiedOptions;\n }\n\n if (this.notAllowedOption()) {\n this.filteredOptions.set(\n currentOptions.filter(\n (option: any): boolean =>\n JSON.stringify(option) !== JSON.stringify(this.notAllowedOption()),\n ),\n );\n } else {\n this.filteredOptions.set(currentOptions);\n }\n }\n\n /**\n * Define el texto a utilizar para la búsqueda\n */\n private getAutocompleteSearchText(): string {\n const value = this.component.value;\n if (typeof value === \"object\" && value !== null) {\n // Si el valor es un objeto, usa displayFn para obtener el texto\n return this.displayFn(value);\n } else if (typeof value === \"string\") {\n return value;\n }\n return \"\";\n }\n\n // --- Métodos de ControlValueAccessor ---\n propagateChange = (_: any): void => {};\n\n registerOnChange(fn: (_: any) => void): void {\n this.propagateChange = fn;\n }\n\n registerOnTouched(): void {}\n\n /**\n * Recibe el valor desde el FormControl externo.\n */\n writeValue(value: any): void {\n // Establecer la bandera para indicar que el cambio viene de un setValue programático\n this._isOptionSelected = typeof value === \"object\" && value !== null;\n this.component.setValue(value, { emitEvent: false }); // No emitir evento para evitar bucles.\n\n this._selectedElement = value\n ? this.valueId && typeof value === \"object\"\n ? value?.id\n : value\n : null;\n\n // Actualizar _lastSearchText basado en el valor que se está escribiendo.\n // Si el valor es nulo, _lastSearchText también debe ser nulo o vacío\n if (value) {\n this._lastSearchText = this.displayFn(value);\n console.log(\n \"writeValue: Último texto de búsqueda establecido a:\",\n this._lastSearchText,\n );\n } else {\n this._lastSearchText = \"\";\n console.log(\"writeValue: Último texto de búsqueda limpiado.\");\n }\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.disabled.set(isDisabled);\n if (isDisabled) {\n this.component.disable();\n } else {\n this.component.enable();\n }\n }\n\n /**\n * Función para mostrar los elementos seleccionados\n */\n public displayFn = (value: any): string => {\n if (!value) {\n return \"\";\n }\n // Si el valor ya es una cadena, devuélvelo directamente\n if (typeof value === \"string\") {\n return value;\n }\n\n let displayText: string = \"\";\n const options = this.displayOptions || GENERAL_DISPLAY_OPTIONS;\n\n options?.firthLabel?.forEach((field: any): void => {\n if (field?.type === DisplayOptionItemType.PATH) {\n displayText +=\n UtilsService.resolvePropertyByPath(value, field?.path) || \"\";\n } else {\n displayText += field?.divider || \"\";\n }\n });\n\n return displayText;\n };\n\n /**\n * Acción al limpiar el valor del input\n */\n public clear(trigger: MatAutocompleteTrigger): void {\n this.clearElement.emit(this.component.value);\n this.clearInternalState(); // Usa el método auxiliar para limpiar\n this._zone.run((): void => {\n setTimeout((): void => {\n trigger.openPanel(); // Reabrir el panel después de borrar\n this.getAutocompleteByTextHandler(\"\"); // Cargar opciones iniciales (o todas) después de borrar\n }, 100);\n });\n }\n\n /**\n * Acción al enfocar el elemento\n */\n public onFocus(): void {\n console.log(\"On focus: El panel será abierto por el trigger.\");\n // NOTA CLAVE: Ya NO disparamos getAutocompleteByTextHandler aquí directamente.\n // La lógica de carga inicial cuando el panel se abre se gestiona\n // en la suscripción a `this.matAutocomplete.opened` en `ngAfterViewInit`.\n // Esto es crucial para evitar doble disparo, especialmente en dispositivos táctiles.\n // El openPanel() lo maneja el trigger en el HTML, lo cual a su vez dispara matAutocomplete.opened.\n }\n\n public optionSelected($event: any): void {\n const selectedValue = $event?.option?.value;\n if (selectedValue) {\n this._isOptionSelected = true; // Establecer la bandera de selección\n this._selectedElement = selectedValue;\n this.selectElement.emit(selectedValue);\n\n if (this.valueId && typeof selectedValue === \"object\") {\n this.propagateChange(selectedValue?.id);\n } else {\n this.propagateChange(selectedValue);\n }\n // Cuando un ítem es seleccionado, actualizar _lastSearchText con su valor de display.\n // Esto es crucial para que el valueChanges no vuelva a disparar una búsqueda para este valor.\n this._lastSearchText = this.displayFn(selectedValue);\n console.log(\n \"Opción seleccionada. Último texto de búsqueda establecido a:\",\n this._lastSearchText,\n );\n } else {\n // Si se deselecciona o selecciona nulo\n console.log(\n \"La opción seleccionada es nula o indefinida, limpiando el estado.\",\n );\n this.clearInternalState();\n }\n }\n\n /**\n * Maneja el evento de scroll en el panel del autocompletado para cargar más datos.\n */\n onScroll(event: Event): void {\n const element = event.target as HTMLElement;\n const scrollPosition = element.scrollTop + element.clientHeight;\n const scrollHeight = element.scrollHeight;\n const threshold = 50; // Píxeles antes del final para cargar más\n\n if (\n scrollHeight - scrollPosition <= threshold &&\n !this.loading() &&\n this.hasMore()\n ) {\n console.log(\"Cargando más datos por scroll infinito...\");\n // Usar el texto de búsqueda actual (que puede ser el texto del ítem seleccionado o lo que el usuario escribió)\n this.getAutocompleteByTextHandler(this.getAutocompleteSearchText());\n }\n }\n}\n\n/**\n * Validación personalizada para la selección de elementos\n */\nexport function autocompleteValidator(\n control: AbstractControl,\n): ValidationErrors | null {\n // Un valor válido es un objeto no nulo que tiene una propiedad 'id'.\n // Esto asegura que realmente se ha seleccionado un objeto del autocompletado, no solo texto libre.\n // Si el control está vacío, no se aplica esta validación aquí, sino la de 'Validators.required' si está presente.\n if (\n control.value === null ||\n typeof control.value === \"undefined\" ||\n control.value === \"\"\n ) {\n return null; // Deja que Validators.required maneje si está vacío.\n }\n\n if (\n typeof control?.value === \"object\" &&\n control?.value !== null &&\n \"id\" in control.value\n ) {\n return null;\n }\n // Si el valor es una cadena (texto libre) y debería ser un objeto seleccionado.\n return { invalidSelection: true };\n}\n","<mat-form-field\n [floatLabel]=\"floatLabel\"\n class=\"w-100\"\n [appearance]=\"appearance\"\n [color]=\"color\"\n [subscriptSizing]=\"subscriptSizing\"\n>\n @if (showLabel) {\n <mat-label>{{ label | translate }}</mat-label>\n } @if (showSuffix) {\n <mat-icon matSuffix>{{ suffixIcon ?? \"search\" }}</mat-icon>\n }\n <input\n #inputText\n #trigger=\"matAutocompleteTrigger\"\n (focus)=\"onFocus()\"\n [formControl]=\"component\"\n type=\"text\"\n [matAutocomplete]=\"auto\"\n [placeholder]=\"placeholder | translate\"\n aria-label=\"autocomplete\"\n autocomplete=\"off\"\n matInput\n [required]=\"required()\"\n />\n @if (!loading() && component.value) {\n <button\n (click)=\"clear(trigger)\"\n [disabled]=\"disabled()\"\n aria-label=\"Clear\"\n mat-icon-button\n matSuffix\n >\n <mat-icon>close</mat-icon>\n </button>\n } @if (loading()) {\n <button aria-label=\"search\" mat-icon-button matSuffix>\n <mat-spinner [value]=\"90\" color=\"accent\" diameter=\"25\"></mat-spinner>\n </button>\n }\n <mat-autocomplete\n #auto=\"matAutocomplete\"\n [displayWith]=\"displayFn\"\n [requireSelection]=\"requireSelection\"\n (optionSelected)=\"optionSelected($event)\"\n >\n @for (option of filteredOptions(); track option) {\n <mat-option [value]=\"option\">\n @if (!displayOptions && !detailsTemplate) {\n {{ option?.name | i18n: translateService.currentLang }}\n } @if (!detailsTemplate) {\n <div class=\"display-options\">\n <span [ngStyle]=\"{'line-height': displayOptions?.secondLabel ? '16px' : ''}\">\n {{\n option | resolvePropertyPath : displayOptions.firthLabel\n | i18n : translateService.currentLang\n }}\n </span>\n @if (displayOptions?.secondLabel) {\n <span class=\"mat-caption\">\n {{\n option | resolvePropertyPath : displayOptions.secondLabel\n | i18n : translateService.currentLang\n }}\n </span>\n }\n </div>\n } @if (detailsTemplate) {\n <ng-container\n *ngTemplateOutlet=\"detailsTemplate; context: { $implicit: option }\"\n ></ng-container>\n }\n </mat-option>\n }\n </mat-autocomplete>\n\n @if (component.invalid && component.touched) {\n <mat-error>\n {{ 'Este campo es requerido.' | translate }}\n </mat-error>\n }\n</mat-form-field>\n","/*\n * Public API Surface of guachos-general-autocomplete\n */\n\nexport * from './utils/constants/constants';\nexport * from './lib/guachos-general-autocomplete.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
@@ -63,41 +63,43 @@ export declare class GuajiritosGeneralAutocomplete implements ControlValueAccess
|
|
63
63
|
set clearData(value: Subject<void>);
|
64
64
|
set initialValue(value: any);
|
65
65
|
/**
|
66
|
-
*
|
66
|
+
* Añade o elimina restricciones de búsqueda
|
67
67
|
*/
|
68
68
|
set restrictions(restrictions: RestrictionFilter[]);
|
69
69
|
/**
|
70
|
-
*
|
70
|
+
* Añade o elimina la validación de requerido
|
71
71
|
*/
|
72
72
|
set isRequired(required: boolean);
|
73
73
|
/**
|
74
|
-
*
|
74
|
+
* Define si se realiza una búsqueda cuando el elemento está en foco
|
75
75
|
*/
|
76
76
|
set doFocus(focusSubject: Subject<void>);
|
77
77
|
set notAllowedElements(element: any);
|
78
78
|
/**
|
79
|
-
*
|
80
|
-
*
|
79
|
+
* Reinicia el estado de paginación y opciones del autocompletado.
|
80
|
+
* Centraliza la lógica para evitar duplicación.
|
81
81
|
*/
|
82
82
|
private resetAutocompleteState;
|
83
83
|
/**
|
84
|
-
*
|
84
|
+
* Suscripción a los cambios del input de búsqueda
|
85
85
|
*/
|
86
86
|
private subscribeToComponentChanges;
|
87
87
|
ngAfterViewInit(): void;
|
88
88
|
/**
|
89
|
-
*
|
89
|
+
* Método auxiliar para limpiar el estado interno del autocompletado.
|
90
|
+
* Este método ahora se encarga de la limpieza profunda, incluyendo el valor del FormControl y la propagación.
|
91
|
+
* @param resetLastSearchText - Si es true, reinicia _lastSearchText a una cadena vacía. Por defecto es true.
|
90
92
|
*/
|
91
93
|
private clearInternalState;
|
92
94
|
/**
|
93
|
-
*
|
94
|
-
*
|
95
|
-
* @param text -
|
95
|
+
* Busca elementos para mostrar en el componente de autocompletado.
|
96
|
+
* Ahora soporta paginación.
|
97
|
+
* @param text - Texto a buscar
|
96
98
|
*/
|
97
99
|
private getAutocompleteByTextHandler;
|
98
100
|
private filterOptionsBasedOnNotAllowed;
|
99
101
|
/**
|
100
|
-
*
|
102
|
+
* Define el texto a utilizar para la búsqueda
|
101
103
|
*/
|
102
104
|
private getAutocompleteSearchText;
|
103
105
|
propagateChange: (_: any) => void;
|
@@ -109,26 +111,26 @@ export declare class GuajiritosGeneralAutocomplete implements ControlValueAccess
|
|
109
111
|
writeValue(value: any): void;
|
110
112
|
setDisabledState(isDisabled: boolean): void;
|
111
113
|
/**
|
112
|
-
*
|
114
|
+
* Función para mostrar los elementos seleccionados
|
113
115
|
*/
|
114
116
|
displayFn: (value: any) => string;
|
115
117
|
/**
|
116
|
-
*
|
118
|
+
* Acción al limpiar el valor del input
|
117
119
|
*/
|
118
120
|
clear(trigger: MatAutocompleteTrigger): void;
|
119
121
|
/**
|
120
|
-
*
|
122
|
+
* Acción al enfocar el elemento
|
121
123
|
*/
|
122
124
|
onFocus(): void;
|
123
125
|
optionSelected($event: any): void;
|
124
126
|
/**
|
125
|
-
*
|
127
|
+
* Maneja el evento de scroll en el panel del autocompletado para cargar más datos.
|
126
128
|
*/
|
127
129
|
onScroll(event: Event): void;
|
128
130
|
static ɵfac: i0.ɵɵFactoryDeclaration<GuajiritosGeneralAutocomplete, never>;
|
129
131
|
static ɵcmp: i0.ɵɵComponentDeclaration<GuajiritosGeneralAutocomplete, "guajiritos-general-autocomplete", never, { "floatLabel": { "alias": "floatLabel"; "required": false; }; "color": { "alias": "color"; "required": false; }; "appearance": { "alias": "appearance"; "required": false; }; "subscriptSizing": { "alias": "subscriptSizing"; "required": false; }; "bodyRequest": { "alias": "bodyRequest"; "required": false; }; "debounceTimeValue": { "alias": "debounceTimeValue"; "required": false; }; "detailsTemplate": { "alias": "detailsTemplate"; "required": false; }; "label": { "alias": "label"; "required": false; }; "showLabel": { "alias": "showLabel"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "field": { "alias": "field"; "required": false; }; "filterString": { "alias": "filterString"; "required": false; }; "displayOptions": { "alias": "displayOptions"; "required": false; }; "withoutPaddingBottom": { "alias": "withoutPaddingBottom"; "required": false; }; "valueId": { "alias": "valueId"; "required": false; }; "showSuffix": { "alias": "showSuffix"; "required": false; }; "requireSelection": { "alias": "requireSelection"; "required": false; }; "order": { "alias": "order"; "required": false; }; "serviceConfig": { "alias": "serviceConfig"; "required": false; }; "suffixIcon": { "alias": "suffixIcon"; "required": false; }; "removeProperties": { "alias": "removeProperties"; "required": false; }; "modifyResultFn": { "alias": "modifyResultFn"; "required": false; }; "url": { "alias": "url"; "required": false; }; "limit": { "alias": "limit"; "required": false; }; "clearData": { "alias": "clearData"; "required": false; }; "initialValue": { "alias": "initialValue"; "required": false; }; "restrictions": { "alias": "restrictions"; "required": false; }; "isRequired": { "alias": "isRequired"; "required": false; }; "doFocus": { "alias": "doFocus"; "required": false; }; "notAllowedElements": { "alias": "notAllowedElements"; "required": false; }; }, { "selectElement": "selectElement"; "clearElement": "clearElement"; }, never, never, true, never>;
|
130
132
|
}
|
131
133
|
/**
|
132
|
-
*
|
134
|
+
* Validación personalizada para la selección de elementos
|
133
135
|
*/
|
134
136
|
export declare function autocompleteValidator(control: AbstractControl): ValidationErrors | null;
|