@jvsoft/utils 1.0.0-alpha.6 → 1.0.0-alpha.7

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.
Files changed (43) hide show
  1. package/README.md +5 -0
  2. package/directives/autocomplete-match-validator.directive.d.ts +10 -0
  3. package/directives/autocomplete.directive.d.ts +23 -0
  4. package/directives/index.d.ts +5 -0
  5. package/directives/public-api.d.ts +2 -0
  6. package/fesm2022/jvsoft-utils-directives.mjs +150 -0
  7. package/fesm2022/jvsoft-utils-directives.mjs.map +1 -0
  8. package/fesm2022/jvsoft-utils.mjs +246 -17
  9. package/fesm2022/jvsoft-utils.mjs.map +1 -1
  10. package/package.json +9 -5
  11. package/public-api.d.ts +5 -4
  12. package/{functions → src/functions}/mat-form-controls/autocomplete.d.ts +21 -2
  13. package/src/pipes/display-with.pipe.d.ts +14 -0
  14. package/{pipes → src/pipes}/public-api.d.ts +1 -0
  15. /package/{classes → src/classes}/data-model.d.ts +0 -0
  16. /package/{functions → src/functions}/base64.d.ts +0 -0
  17. /package/{functions → src/functions}/browser.d.ts +0 -0
  18. /package/{functions → src/functions}/crypto-js.d.ts +0 -0
  19. /package/{functions → src/functions}/date.d.ts +0 -0
  20. /package/{functions → src/functions}/dev-log.d.ts +0 -0
  21. /package/{functions → src/functions}/email.d.ts +0 -0
  22. /package/{functions → src/functions}/file.d.ts +0 -0
  23. /package/{functions → src/functions}/forms.d.ts +0 -0
  24. /package/{functions → src/functions}/http-client.d.ts +0 -0
  25. /package/{functions → src/functions}/local-storage.d.ts +0 -0
  26. /package/{functions → src/functions}/mat-form-controls/index.d.ts +0 -0
  27. /package/{functions → src/functions}/number.d.ts +0 -0
  28. /package/{functions → src/functions}/object-transformation.d.ts +0 -0
  29. /package/{functions → src/functions}/objects-arrays.d.ts +0 -0
  30. /package/{functions → src/functions}/public-api.d.ts +0 -0
  31. /package/{functions → src/functions}/string.d.ts +0 -0
  32. /package/{functions → src/functions}/sweetalert.d.ts +0 -0
  33. /package/{functions → src/functions}/utiles.d.ts +0 -0
  34. /package/{interfaces → src/interfaces}/datos.d.ts +0 -0
  35. /package/{interfaces → src/interfaces}/public-api.d.ts +0 -0
  36. /package/{pipes → src/pipes}/data-en-lista.pipe.d.ts +0 -0
  37. /package/{pipes → src/pipes}/date-diff-string.pipe.d.ts +0 -0
  38. /package/{pipes → src/pipes}/filtro.pipe.d.ts +0 -0
  39. /package/{pipes → src/pipes}/form-control-is-required.pipe.d.ts +0 -0
  40. /package/{pipes → src/pipes}/json-parse.pipe.d.ts +0 -0
  41. /package/{pipes → src/pipes}/no-sanitize.pipe.d.ts +0 -0
  42. /package/{pipes → src/pipes}/tipo-valor-funcion.pipe.d.ts +0 -0
  43. /package/{pipes → src/pipes}/zero-fill.pipe.d.ts +0 -0
package/README.md CHANGED
@@ -58,6 +58,11 @@ ng e2e
58
58
 
59
59
  Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
60
60
 
61
+ ## Documentación
62
+
63
+ - [Directiva JvAutocomplete](./docs/autocomplete.md): Guía detallada de uso, ejemplos y referencia de la API.
64
+ - [Utilidades de Logging](./docs/logging.md): Guía para el uso de logs en desarrollo.
65
+
61
66
  ## Additional Resources
62
67
 
63
68
  For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
@@ -0,0 +1,10 @@
1
+ import { AbstractControl, ValidationErrors, Validator } from '@angular/forms';
2
+ import * as i0 from "@angular/core";
3
+ export declare class AutocompleteMatchValidatorDirective implements Validator {
4
+ opciones: import("@angular/core").InputSignal<any[]>;
5
+ formControlName: import("@angular/core").InputSignal<any>;
6
+ idLista: import("@angular/core").InputSignal<string | undefined>;
7
+ validate(control: AbstractControl): ValidationErrors | null;
8
+ static ɵfac: i0.ɵɵFactoryDeclaration<AutocompleteMatchValidatorDirective, never>;
9
+ static ɵdir: i0.ɵɵDirectiveDeclaration<AutocompleteMatchValidatorDirective, "[jvsAutocompleteMatch]", never, { "opciones": { "alias": "jvsAutocompleteMatch"; "required": false; "isSignal": true; }; "formControlName": { "alias": "formControlName"; "required": false; "isSignal": true; }; "idLista": { "alias": "idLista"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
10
+ }
@@ -0,0 +1,23 @@
1
+ import { OnInit } from '@angular/core';
2
+ import * as i0 from "@angular/core";
3
+ export declare class JvsAutocompleteDirective implements OnInit {
4
+ private readonly destroyRef;
5
+ private readonly ngControl;
6
+ private readonly focus$;
7
+ data: import("@angular/core").InputSignal<any[] | null>;
8
+ fields: import("@angular/core").InputSignal<string | string[]>;
9
+ typeReq: import("@angular/core").InputSignal<string>;
10
+ queryService: import("@angular/core").InputSignal<any>;
11
+ minLength: import("@angular/core").InputSignal<number>;
12
+ dataExtra: import("@angular/core").InputSignal<any>;
13
+ anonimo: import("@angular/core").InputSignal<boolean>;
14
+ debounce: import("@angular/core").InputSignal<number>;
15
+ filtered: import("@angular/core").OutputEmitterRef<any[]>;
16
+ loading: import("@angular/core").OutputEmitterRef<boolean>;
17
+ onFocus(): void;
18
+ ngOnInit(): void;
19
+ private filterLocal;
20
+ private fetchApi;
21
+ static ɵfac: i0.ɵɵFactoryDeclaration<JvsAutocompleteDirective, never>;
22
+ static ɵdir: i0.ɵɵDirectiveDeclaration<JvsAutocompleteDirective, "[jvsAutocomplete]", never, { "data": { "alias": "data"; "required": false; "isSignal": true; }; "fields": { "alias": "fields"; "required": false; "isSignal": true; }; "typeReq": { "alias": "typeReq"; "required": false; "isSignal": true; }; "queryService": { "alias": "queryService"; "required": false; "isSignal": true; }; "minLength": { "alias": "minLength"; "required": false; "isSignal": true; }; "dataExtra": { "alias": "dataExtra"; "required": false; "isSignal": true; }; "anonimo": { "alias": "anonimo"; "required": false; "isSignal": true; }; "debounce": { "alias": "debounce"; "required": false; "isSignal": true; }; }, { "filtered": "filtered"; "loading": "loading"; }, never, never, true, never>;
23
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="@jvsoft/utils/directives" />
5
+ export * from './public-api';
@@ -0,0 +1,2 @@
1
+ export * from './autocomplete-match-validator.directive';
2
+ export * from './autocomplete.directive';
@@ -0,0 +1,150 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, forwardRef, Directive, inject, DestroyRef, output, HostListener } from '@angular/core';
3
+ import { NG_VALIDATORS, NgControl } from '@angular/forms';
4
+ import { Subject, merge, debounceTime, startWith, distinctUntilChanged, tap, switchMap, of, map, finalize } from 'rxjs';
5
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
6
+
7
+ class AutocompleteMatchValidatorDirective {
8
+ opciones = input([], { alias: 'jvsAutocompleteMatch' });
9
+ formControlName = input();
10
+ idLista = input();
11
+ validate(control) {
12
+ const idLista = this.idLista() ?? this.formControlName();
13
+ const value = control.value;
14
+ const opciones = this.opciones();
15
+ if (!value)
16
+ return null;
17
+ if (!opciones) {
18
+ console.error('Debe definir opciones para el validador jvsAutocompleteMatch');
19
+ return { itemSelected: true };
20
+ }
21
+ const encontrado = opciones.some(item => typeof value === 'object'
22
+ ? item[idLista] === value[idLista]
23
+ : item[idLista] === value);
24
+ return encontrado ? null : { itemSelected: true };
25
+ }
26
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AutocompleteMatchValidatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
27
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: AutocompleteMatchValidatorDirective, isStandalone: true, selector: "[jvsAutocompleteMatch]", inputs: { opciones: { classPropertyName: "opciones", publicName: "jvsAutocompleteMatch", isSignal: true, isRequired: false, transformFunction: null }, formControlName: { classPropertyName: "formControlName", publicName: "formControlName", isSignal: true, isRequired: false, transformFunction: null }, idLista: { classPropertyName: "idLista", publicName: "idLista", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
28
+ {
29
+ provide: NG_VALIDATORS,
30
+ useExisting: forwardRef(() => AutocompleteMatchValidatorDirective),
31
+ multi: true,
32
+ },
33
+ ], ngImport: i0 });
34
+ }
35
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AutocompleteMatchValidatorDirective, decorators: [{
36
+ type: Directive,
37
+ args: [{
38
+ selector: '[jvsAutocompleteMatch]',
39
+ providers: [
40
+ {
41
+ provide: NG_VALIDATORS,
42
+ useExisting: forwardRef(() => AutocompleteMatchValidatorDirective),
43
+ multi: true,
44
+ },
45
+ ],
46
+ standalone: true
47
+ }]
48
+ }] });
49
+
50
+ class JvsAutocompleteDirective {
51
+ destroyRef = inject(DestroyRef);
52
+ ngControl = inject(NgControl, { optional: true });
53
+ focus$ = new Subject();
54
+ // Signal-based Inputs
55
+ data = input(null);
56
+ fields = input('');
57
+ typeReq = input('');
58
+ queryService = input(null);
59
+ minLength = input(3);
60
+ dataExtra = input({});
61
+ anonimo = input(false);
62
+ debounce = input(300);
63
+ // Modern Outputs
64
+ filtered = output();
65
+ loading = output();
66
+ onFocus() {
67
+ this.focus$.next();
68
+ }
69
+ ngOnInit() {
70
+ const control = this.ngControl;
71
+ if (!control || !control.valueChanges) {
72
+ console.warn('JvsAutocompleteDirective: No se encontró ngControl o valueChanges. Asegúrate de que el input tenga un formControl o formControlName.');
73
+ return;
74
+ }
75
+ // Si es data local, bajamos el debounce por defecto a 0 si no se ha especificado
76
+ const isLocal = this.data() && !this.typeReq();
77
+ const actualDebounce = (isLocal && this.debounce() === 300) ? 0 : this.debounce();
78
+ merge(control.valueChanges.pipe(debounceTime(actualDebounce)), this.focus$).pipe(takeUntilDestroyed(this.destroyRef), startWith(control.value), distinctUntilChanged(), tap(() => {
79
+ if (this.typeReq())
80
+ this.loading.emit(true);
81
+ }), switchMap(() => {
82
+ const value = control.value;
83
+ // Si el valor es un objeto (proviene de seleccionar una opción), no volvemos a filtrar
84
+ if (typeof value === 'object' && value !== null) {
85
+ if (this.typeReq())
86
+ this.loading.emit(false);
87
+ return of(null);
88
+ }
89
+ if (this.typeReq() && this.queryService()) {
90
+ return this.fetchApi(value?.toString() || '');
91
+ }
92
+ else if (this.data()) {
93
+ const res = this.filterLocal(value?.toString() || '');
94
+ return of(res);
95
+ }
96
+ if (this.typeReq())
97
+ this.loading.emit(false);
98
+ return of([]);
99
+ })).subscribe((result) => {
100
+ if (result !== null) {
101
+ this.filtered.emit(result);
102
+ }
103
+ });
104
+ }
105
+ filterLocal(value) {
106
+ const data = this.data();
107
+ if (!value)
108
+ return data || [];
109
+ const search = value.toLowerCase();
110
+ const rawFields = this.fields();
111
+ const fields = Array.isArray(rawFields) ? rawFields : [rawFields];
112
+ return (data || []).filter(item => {
113
+ return fields.some(field => {
114
+ const val = item[field];
115
+ return val && val.toString().toLowerCase().includes(search);
116
+ });
117
+ });
118
+ }
119
+ fetchApi(value) {
120
+ const typeReq = this.typeReq();
121
+ const queryService = this.queryService();
122
+ if (!value || value.length < this.minLength()) {
123
+ this.loading.emit(false);
124
+ return of([]);
125
+ }
126
+ return queryService.getDataMethod('GET', typeReq, {
127
+ ...this.dataExtra(),
128
+ txtBuscar: value
129
+ }, this.anonimo()).pipe(map((res) => res[typeReq] ?? []), finalize(() => this.loading.emit(false)));
130
+ }
131
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsAutocompleteDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
132
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: JvsAutocompleteDirective, isStandalone: true, selector: "[jvsAutocomplete]", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null }, typeReq: { classPropertyName: "typeReq", publicName: "typeReq", isSignal: true, isRequired: false, transformFunction: null }, queryService: { classPropertyName: "queryService", publicName: "queryService", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, dataExtra: { classPropertyName: "dataExtra", publicName: "dataExtra", isSignal: true, isRequired: false, transformFunction: null }, anonimo: { classPropertyName: "anonimo", publicName: "anonimo", isSignal: true, isRequired: false, transformFunction: null }, debounce: { classPropertyName: "debounce", publicName: "debounce", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filtered: "filtered", loading: "loading" }, host: { listeners: { "focus": "onFocus()" } }, ngImport: i0 });
133
+ }
134
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsAutocompleteDirective, decorators: [{
135
+ type: Directive,
136
+ args: [{
137
+ selector: '[jvsAutocomplete]',
138
+ standalone: true
139
+ }]
140
+ }], propDecorators: { onFocus: [{
141
+ type: HostListener,
142
+ args: ['focus']
143
+ }] } });
144
+
145
+ /**
146
+ * Generated bundle index. Do not edit.
147
+ */
148
+
149
+ export { AutocompleteMatchValidatorDirective, JvsAutocompleteDirective };
150
+ //# sourceMappingURL=jvsoft-utils-directives.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jvsoft-utils-directives.mjs","sources":["../../../projects/utils/directives/autocomplete-match-validator.directive.ts","../../../projects/utils/directives/autocomplete.directive.ts","../../../projects/utils/directives/jvsoft-utils-directives.ts"],"sourcesContent":["import { Directive, forwardRef, input } from '@angular/core';\nimport { AbstractControl, NG_VALIDATORS, ValidationErrors, Validator } from '@angular/forms';\n\n@Directive({\n selector: '[jvsAutocompleteMatch]',\n providers: [\n {\n provide: NG_VALIDATORS,\n useExisting: forwardRef(() => AutocompleteMatchValidatorDirective),\n multi: true,\n },\n ],\n standalone: true\n})\nexport class AutocompleteMatchValidatorDirective implements Validator {\n opciones = input<any[]>([], { alias: 'jvsAutocompleteMatch' });\n formControlName = input<any>();\n idLista = input<string>();\n\n validate(control: AbstractControl): ValidationErrors | null {\n const idLista = this.idLista() ?? this.formControlName();\n const value = control.value;\n const opciones = this.opciones();\n\n if (!value) return null;\n\n if (!opciones) {\n console.error('Debe definir opciones para el validador jvsAutocompleteMatch');\n return { itemSelected: true };\n }\n\n const encontrado = opciones.some(item =>\n typeof value === 'object'\n ? item[idLista] === value[idLista]\n : item[idLista] === value\n );\n\n return encontrado ? null : { itemSelected: true };\n }\n}\n","import { Directive, ElementRef, EventEmitter, inject, OnInit, DestroyRef, HostListener, input, output } from '@angular/core';\nimport { NgControl } from '@angular/forms';\nimport { debounceTime, distinctUntilChanged, isObservable, of, switchMap, takeUntil, tap, finalize, map, Observable, startWith, merge, Subject } from 'rxjs';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\n@Directive({\n selector: '[jvsAutocomplete]',\n standalone: true\n})\nexport class JvsAutocompleteDirective implements OnInit {\n private readonly destroyRef = inject(DestroyRef);\n private readonly ngControl = inject(NgControl, { optional: true });\n private readonly focus$ = new Subject<void>();\n \n // Signal-based Inputs\n data = input<any[] | null>(null);\n fields = input<string | string[]>('');\n typeReq = input<string>('');\n queryService = input<any>(null);\n minLength = input<number>(3);\n dataExtra = input<any>({});\n anonimo = input<boolean>(false);\n debounce = input<number>(300);\n \n // Modern Outputs\n filtered = output<any[]>();\n loading = output<boolean>();\n\n @HostListener('focus')\n onFocus() {\n this.focus$.next();\n }\n\n ngOnInit(): void {\n const control = this.ngControl;\n if (!control || !control.valueChanges) {\n console.warn('JvsAutocompleteDirective: No se encontró ngControl o valueChanges. Asegúrate de que el input tenga un formControl o formControlName.');\n return;\n }\n\n // Si es data local, bajamos el debounce por defecto a 0 si no se ha especificado\n const isLocal = this.data() && !this.typeReq();\n const actualDebounce = (isLocal && this.debounce() === 300) ? 0 : this.debounce();\n\n merge(\n control.valueChanges.pipe(debounceTime(actualDebounce)),\n this.focus$\n ).pipe(\n takeUntilDestroyed(this.destroyRef),\n startWith(control.value),\n distinctUntilChanged(),\n tap(() => {\n if (this.typeReq()) this.loading.emit(true);\n }),\n switchMap((): Observable<any[] | null> => {\n const value = control.value;\n // Si el valor es un objeto (proviene de seleccionar una opción), no volvemos a filtrar\n if (typeof value === 'object' && value !== null) {\n if (this.typeReq()) this.loading.emit(false);\n return of(null);\n }\n\n if (this.typeReq() && this.queryService()) {\n return this.fetchApi(value?.toString() || '');\n } else if (this.data()) {\n const res = this.filterLocal(value?.toString() || '');\n return of(res);\n }\n \n if (this.typeReq()) this.loading.emit(false);\n return of([]);\n })\n ).subscribe((result) => {\n if (result !== null) {\n this.filtered.emit(result);\n }\n });\n }\n\n private filterLocal(value: string): any[] {\n const data = this.data();\n if (!value) return data || [];\n \n const search = value.toLowerCase();\n const rawFields = this.fields();\n const fields = Array.isArray(rawFields) ? rawFields : [rawFields];\n\n return (data || []).filter(item => {\n return fields.some(field => {\n const val = item[field];\n return val && val.toString().toLowerCase().includes(search);\n });\n });\n }\n\n private fetchApi(value: string): Observable<any[]> {\n const typeReq = this.typeReq();\n const queryService = this.queryService();\n\n if (!value || value.length < this.minLength()) {\n this.loading.emit(false);\n return of([]);\n }\n\n return queryService.getDataMethod('GET', typeReq, {\n ...this.dataExtra(),\n txtBuscar: value\n }, this.anonimo()).pipe(\n map((res: any) => res[typeReq] ?? []),\n finalize(() => this.loading.emit(false))\n );\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
- import { Validators, FormGroup, FormControl, FormArray } from '@angular/forms';
2
- import { untilDestroyed } from '@ngneat/until-destroy';
3
- import { startWith, debounceTime, tap, isObservable, switchMap, of, finalize } from 'rxjs';
1
+ import { Validators, FormGroup, FormControl, FormArray, NG_VALIDATORS, NgControl } from '@angular/forms';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, DestroyRef, Pipe, input, forwardRef, Directive, output, HostListener } from '@angular/core';
4
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
5
+ import { tap, startWith, debounceTime, isObservable, switchMap, of, finalize, Subject, merge, distinctUntilChanged, map as map$1 } from 'rxjs';
4
6
  import { map } from 'rxjs/operators';
5
7
  import { Buffer } from 'buffer';
6
8
  import CryptoJS from 'crypto-js';
@@ -10,8 +12,6 @@ import { ReactiveFormConfig } from '@rxweb/reactive-form-validators';
10
12
  import moment from 'moment';
11
13
  import swal from 'sweetalert2';
12
14
  import { jwtDecode } from 'jwt-decode';
13
- import * as i0 from '@angular/core';
14
- import { Pipe } from '@angular/core';
15
15
  import * as i1 from '@angular/platform-browser';
16
16
 
17
17
  function deepMerge(source, target) {
@@ -287,6 +287,22 @@ function filtrarDatosLocal(data, value, campoBuscar) {
287
287
  });
288
288
  }
289
289
 
290
+ /**
291
+ * Intenta obtener el DestroyRef desde el llamador (objThis/control)
292
+ * o inyectándolo si estamos en un contexto de inyección.
293
+ */
294
+ function obtenerDestroyRef(caller, manualDRef, fnName = 'N/A') {
295
+ let dRef = manualDRef || caller?.['destroyRef'] || caller?.['_destroyRef'];
296
+ if (!dRef) {
297
+ try {
298
+ dRef = inject(DestroyRef, { optional: true });
299
+ }
300
+ catch (e) {
301
+ console.warn(`${fnName}: Falló inject(DestroyRef) (fuera del contexto de inyección). Pasa el destroyRef explícitamente o decláralo en el componente para habilitar la limpieza.`);
302
+ }
303
+ }
304
+ return dRef ?? undefined;
305
+ }
290
306
  function mostrarValorEnBusqueda(campos, idxSel) {
291
307
  const impDataMostrar = () => {
292
308
  let vD;
@@ -344,8 +360,12 @@ function mostrarValorEnBusqueda(campos, idxSel) {
344
360
  }
345
361
  return '';
346
362
  }
363
+ /**
364
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
365
+ */
347
366
  function changeSelectData(objThis, dataFiltro) {
348
- objThis['filtrados'][dataFiltro.variableResultado] = dataFiltro.formControl.valueChanges.pipe(untilDestroyed(objThis)).pipe(startWith(''), map(value => {
367
+ const dRef = obtenerDestroyRef(objThis, dataFiltro.destroyRef, 'changeSelectData');
368
+ objThis['filtrados'][dataFiltro.variableResultado] = dataFiltro.formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { })).pipe(startWith(''), map(value => {
349
369
  const varN = dataFiltro.data;
350
370
  if (varN) {
351
371
  if (value) {
@@ -385,14 +405,18 @@ function changeSelectData(objThis, dataFiltro) {
385
405
  return false;
386
406
  }));
387
407
  }
388
- function changeSelect(control, formControl, tipo, campoBuscar, campoFiltro = null) {
408
+ /**
409
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
410
+ */
411
+ function changeSelect(control, formControl, tipo, campoBuscar, campoFiltro = null, destroyRef) {
389
412
  // console.log(formControl);
390
413
  // const formGroup = formControl.parent.controls;
391
414
  // console.warn( Object.keys(formGroup).find(name => formControl === formGroup[name]) || null );
392
415
  if (!campoFiltro) {
393
416
  campoFiltro = tipo;
394
417
  }
395
- control['filtrados'][campoFiltro ?? '__'] = formControl.valueChanges.pipe(untilDestroyed(control)).pipe(startWith(''), map(value => {
418
+ const dRef = obtenerDestroyRef(control, destroyRef, 'changeSelect');
419
+ control['filtrados'][campoFiltro ?? '__'] = formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { })).pipe(startWith(''), map(value => {
396
420
  // console.warn(value);
397
421
  const partes = tipo.split('.');
398
422
  let varN;
@@ -440,12 +464,16 @@ function changeSelect(control, formControl, tipo, campoBuscar, campoFiltro = nul
440
464
  return false;
441
465
  }));
442
466
  }
467
+ /**
468
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
469
+ */
443
470
  function changeSelectDataApi(objThis, dataFiltro) {
444
471
  if (!dataFiltro.variableResultado) {
445
472
  dataFiltro.variableResultado = dataFiltro.tipoReq;
446
473
  }
447
474
  const idFiltrado = dataFiltro.variableResultado;
448
- dataFiltro.formControl.valueChanges.pipe(debounceTime(500), tap(() => {
475
+ const dRef = obtenerDestroyRef(objThis, dataFiltro.destroyRef, 'changeSelectDataApi');
476
+ dataFiltro.formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap(() => {
449
477
  objThis.filtrados[dataFiltro.variableResultado + 'tmp'] = isObservable(objThis.filtrados[idFiltrado]) ? [] : objThis.filtrados[idFiltrado] || [];
450
478
  if (objThis.filtrados[idFiltrado] !== objThis.filtrados[idFiltrado + 'tmp']) {
451
479
  objThis.filtrados[idFiltrado] = [];
@@ -467,8 +495,12 @@ function changeSelectDataApi(objThis, dataFiltro) {
467
495
  objThis.filtrados[idFiltrado] = data[dataFiltro.tipoReq] ?? [];
468
496
  });
469
497
  }
470
- function changeSelectApi(control, queryService, formControl, tipo, dataExtra = {}, dataExtraVariable = null, minLength = 1, anonimo = false) {
471
- formControl.valueChanges.pipe(debounceTime(500), tap((value) => {
498
+ /**
499
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
500
+ */
501
+ function changeSelectApi(control, queryService, formControl, tipo, dataExtra = {}, dataExtraVariable = null, minLength = 1, anonimo = false, destroyRef) {
502
+ const dRef = obtenerDestroyRef(control, destroyRef, 'changeSelectApi');
503
+ formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap((value) => {
472
504
  control['filtrados'][tipo + 'tmp'] = isObservable(control['filtrados'][tipo]) ? [] : control['filtrados'][tipo];
473
505
  if (control['filtrados'][tipo] != control['filtrados'][tipo + 'tmp']) {
474
506
  control['filtrados'][tipo] = [];
@@ -527,9 +559,13 @@ function seleccionarTextoInput$1(event) {
527
559
  * Función genérica para vincular un FormControl con datos desde API o Promise.
528
560
  * Preparada para migrar a signals en el futuro.
529
561
  */
562
+ /**
563
+ * @deprecated Use JvsAutocompleteDirective en su lugar para un enfoque más declarativo y robusto.
564
+ */
530
565
  function changeSelectReformateado(config) {
531
- const { objThis, tipoReq, formControl, queryService, campoId, minLength = 3, dataExtra = {}, dataExtraVariable = [], anonimo = false, variableResultado = tipoReq, } = config;
532
- formControl.valueChanges.pipe(debounceTime(500), tap(() => {
566
+ const { objThis, tipoReq, formControl, queryService, campoId, minLength = 3, dataExtra = {}, dataExtraVariable = [], anonimo = false, variableResultado = tipoReq, destroyRef } = config;
567
+ const dRef = obtenerDestroyRef(objThis, destroyRef, 'changeSelectReformateado');
568
+ formControl.valueChanges.pipe(dRef ? takeUntilDestroyed(dRef) : tap(() => { }), debounceTime(500), tap(() => {
533
569
  objThis.filtrados[variableResultado + 'tmp'] = isObservable(objThis.filtrados[variableResultado])
534
570
  ? []
535
571
  : objThis.filtrados[variableResultado] || [];
@@ -2107,18 +2143,211 @@ function zeroFill(value, digitos, ...args) {
2107
2143
  return new ZeroFillPipe().transform(value, digitos, args);
2108
2144
  }
2109
2145
 
2146
+ class JvsDisplayWithPipe {
2147
+ /**
2148
+ * Retorna una función compatible con [displayWith] de MatAutocomplete.
2149
+ * @param lista La lista de objetos donde buscar.
2150
+ * @param campoId El nombre del campo que coincide con el valor del control (ej: 'iCarreraId').
2151
+ * @param campoValue El nombre del campo (o campos) a mostrar (ej: 'cCarreraNombre' o ['cCodigo', 'cNombre']).
2152
+ * @param opcExtra Lista opcional de objetos extra donde buscar si no se encuentra en la lista principal.
2153
+ */
2154
+ transform(lista, campoId, campoValue, opcExtra) {
2155
+ return (idxSel) => {
2156
+ if (idxSel === null || idxSel === undefined || !lista) {
2157
+ return '';
2158
+ }
2159
+ const impDataMostrar = (vD) => {
2160
+ if (!vD)
2161
+ return '';
2162
+ if (Array.isArray(campoValue)) {
2163
+ return campoValue
2164
+ .map(field => vD[field] ?? '')
2165
+ .filter(val => !!val)
2166
+ .join(' - ');
2167
+ }
2168
+ return vD[campoValue]?.toString() || '';
2169
+ };
2170
+ // Buscar en la lista principal
2171
+ let item;
2172
+ if (campoId === '*object*' || campoId === '*objeto*') {
2173
+ item = lista.find(x => JSON.stringify(x).trim() === JSON.stringify(idxSel).trim());
2174
+ }
2175
+ else {
2176
+ item = lista.find(x => x[campoId] == idxSel);
2177
+ }
2178
+ // Si no se encuentra, buscar en opcExtra
2179
+ if (!item && opcExtra) {
2180
+ if (campoId === '*object*' || campoId === '*objeto*') {
2181
+ item = opcExtra.find(x => JSON.stringify(x).trim() === JSON.stringify(idxSel).trim());
2182
+ }
2183
+ else {
2184
+ item = opcExtra.find(x => x[campoId] == idxSel);
2185
+ }
2186
+ }
2187
+ return item ? impDataMostrar(item).trim() : '';
2188
+ };
2189
+ }
2190
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsDisplayWithPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
2191
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: JvsDisplayWithPipe, isStandalone: true, name: "jvsDisplayWith" });
2192
+ }
2193
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsDisplayWithPipe, decorators: [{
2194
+ type: Pipe,
2195
+ args: [{
2196
+ name: 'jvsDisplayWith',
2197
+ standalone: true
2198
+ }]
2199
+ }] });
2200
+
2110
2201
  // export * from './otros';
2111
2202
 
2203
+ class AutocompleteMatchValidatorDirective {
2204
+ opciones = input([], { alias: 'jvsAutocompleteMatch' });
2205
+ formControlName = input();
2206
+ idLista = input();
2207
+ validate(control) {
2208
+ const idLista = this.idLista() ?? this.formControlName();
2209
+ const value = control.value;
2210
+ const opciones = this.opciones();
2211
+ if (!value)
2212
+ return null;
2213
+ if (!opciones) {
2214
+ console.error('Debe definir opciones para el validador jvsAutocompleteMatch');
2215
+ return { itemSelected: true };
2216
+ }
2217
+ const encontrado = opciones.some(item => typeof value === 'object'
2218
+ ? item[idLista] === value[idLista]
2219
+ : item[idLista] === value);
2220
+ return encontrado ? null : { itemSelected: true };
2221
+ }
2222
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AutocompleteMatchValidatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2223
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: AutocompleteMatchValidatorDirective, isStandalone: true, selector: "[jvsAutocompleteMatch]", inputs: { opciones: { classPropertyName: "opciones", publicName: "jvsAutocompleteMatch", isSignal: true, isRequired: false, transformFunction: null }, formControlName: { classPropertyName: "formControlName", publicName: "formControlName", isSignal: true, isRequired: false, transformFunction: null }, idLista: { classPropertyName: "idLista", publicName: "idLista", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
2224
+ {
2225
+ provide: NG_VALIDATORS,
2226
+ useExisting: forwardRef(() => AutocompleteMatchValidatorDirective),
2227
+ multi: true,
2228
+ },
2229
+ ], ngImport: i0 });
2230
+ }
2231
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AutocompleteMatchValidatorDirective, decorators: [{
2232
+ type: Directive,
2233
+ args: [{
2234
+ selector: '[jvsAutocompleteMatch]',
2235
+ providers: [
2236
+ {
2237
+ provide: NG_VALIDATORS,
2238
+ useExisting: forwardRef(() => AutocompleteMatchValidatorDirective),
2239
+ multi: true,
2240
+ },
2241
+ ],
2242
+ standalone: true
2243
+ }]
2244
+ }] });
2245
+
2246
+ class JvsAutocompleteDirective {
2247
+ destroyRef = inject(DestroyRef);
2248
+ ngControl = inject(NgControl, { optional: true });
2249
+ focus$ = new Subject();
2250
+ // Signal-based Inputs
2251
+ data = input(null);
2252
+ fields = input('');
2253
+ typeReq = input('');
2254
+ queryService = input(null);
2255
+ minLength = input(3);
2256
+ dataExtra = input({});
2257
+ anonimo = input(false);
2258
+ debounce = input(300);
2259
+ // Modern Outputs
2260
+ filtered = output();
2261
+ loading = output();
2262
+ onFocus() {
2263
+ this.focus$.next();
2264
+ }
2265
+ ngOnInit() {
2266
+ const control = this.ngControl;
2267
+ if (!control || !control.valueChanges) {
2268
+ console.warn('JvsAutocompleteDirective: No se encontró ngControl o valueChanges. Asegúrate de que el input tenga un formControl o formControlName.');
2269
+ return;
2270
+ }
2271
+ // Si es data local, bajamos el debounce por defecto a 0 si no se ha especificado
2272
+ const isLocal = this.data() && !this.typeReq();
2273
+ const actualDebounce = (isLocal && this.debounce() === 300) ? 0 : this.debounce();
2274
+ merge(control.valueChanges.pipe(debounceTime(actualDebounce)), this.focus$).pipe(takeUntilDestroyed(this.destroyRef), startWith(control.value), distinctUntilChanged(), tap(() => {
2275
+ if (this.typeReq())
2276
+ this.loading.emit(true);
2277
+ }), switchMap(() => {
2278
+ const value = control.value;
2279
+ // Si el valor es un objeto (proviene de seleccionar una opción), no volvemos a filtrar
2280
+ if (typeof value === 'object' && value !== null) {
2281
+ if (this.typeReq())
2282
+ this.loading.emit(false);
2283
+ return of(null);
2284
+ }
2285
+ if (this.typeReq() && this.queryService()) {
2286
+ return this.fetchApi(value?.toString() || '');
2287
+ }
2288
+ else if (this.data()) {
2289
+ const res = this.filterLocal(value?.toString() || '');
2290
+ return of(res);
2291
+ }
2292
+ if (this.typeReq())
2293
+ this.loading.emit(false);
2294
+ return of([]);
2295
+ })).subscribe((result) => {
2296
+ if (result !== null) {
2297
+ this.filtered.emit(result);
2298
+ }
2299
+ });
2300
+ }
2301
+ filterLocal(value) {
2302
+ const data = this.data();
2303
+ if (!value)
2304
+ return data || [];
2305
+ const search = value.toLowerCase();
2306
+ const rawFields = this.fields();
2307
+ const fields = Array.isArray(rawFields) ? rawFields : [rawFields];
2308
+ return (data || []).filter(item => {
2309
+ return fields.some(field => {
2310
+ const val = item[field];
2311
+ return val && val.toString().toLowerCase().includes(search);
2312
+ });
2313
+ });
2314
+ }
2315
+ fetchApi(value) {
2316
+ const typeReq = this.typeReq();
2317
+ const queryService = this.queryService();
2318
+ if (!value || value.length < this.minLength()) {
2319
+ this.loading.emit(false);
2320
+ return of([]);
2321
+ }
2322
+ return queryService.getDataMethod('GET', typeReq, {
2323
+ ...this.dataExtra(),
2324
+ txtBuscar: value
2325
+ }, this.anonimo()).pipe(map$1((res) => res[typeReq] ?? []), finalize(() => this.loading.emit(false)));
2326
+ }
2327
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsAutocompleteDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
2328
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: JvsAutocompleteDirective, isStandalone: true, selector: "[jvsAutocomplete]", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null }, typeReq: { classPropertyName: "typeReq", publicName: "typeReq", isSignal: true, isRequired: false, transformFunction: null }, queryService: { classPropertyName: "queryService", publicName: "queryService", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, dataExtra: { classPropertyName: "dataExtra", publicName: "dataExtra", isSignal: true, isRequired: false, transformFunction: null }, anonimo: { classPropertyName: "anonimo", publicName: "anonimo", isSignal: true, isRequired: false, transformFunction: null }, debounce: { classPropertyName: "debounce", publicName: "debounce", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filtered: "filtered", loading: "loading" }, host: { listeners: { "focus": "onFocus()" } }, ngImport: i0 });
2329
+ }
2330
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JvsAutocompleteDirective, decorators: [{
2331
+ type: Directive,
2332
+ args: [{
2333
+ selector: '[jvsAutocomplete]',
2334
+ standalone: true
2335
+ }]
2336
+ }], propDecorators: { onFocus: [{
2337
+ type: HostListener,
2338
+ args: ['focus']
2339
+ }] } });
2340
+
2112
2341
  /*
2113
2342
  * Public API Surface of utils
2114
2343
  */
2115
- // export * from './functions/common.function';
2116
- // export * from './lib/utils.component';
2117
- // export * from './lib/utils.service';
2344
+ // export * from './src/functions/common.function';
2345
+ // export * from './src/lib/utils.component';
2346
+ // export * from './src/lib/utils.service';
2118
2347
 
2119
2348
  /**
2120
2349
  * Generated bundle index. Do not edit.
2121
2350
  */
2122
2351
 
2123
- export { DataEnListaPipe, DataModel, DateDiffStringPipe, FiltroPipe, FormControlIsRequiredPipe, JsonParsePipe, NoSanitizePipe, TipoValorFuncionPipe, ZeroFillPipe, b64Decode, b64Encode, buscarPorCampo, changeSelect, changeSelectApi, changeSelectData, changeSelectDataApi, changeSelectReformateado, convertirBytes, dataEnLista, dateDiffString, decodeBase64Object, decodeBase64String, decodeBase64ToBlob, deepClone, deepMerge, delLocalStorage, desencriptar, devError, devGroup, devGroupEnd, devLog, devTable, devTime, devTimeEnd, devWarn, downLoadFileStream, eliminarColumnaPorIndex, eliminarDuplicados, eliminarElementos, encodeBase64File, encodeBase64Object, encodeBase64String, encriptar, esNumero, esPromise, establecerQuitarRequired, extraerDominio, filtrarDatosLocal, formControlIsRequired, formatearFecha, formatearFechaCadena, formatearFechaFormato, generateRandomString, getBrowserName, getCambiarPwd, getDataArchivoFromPath, getFormValidationErrors, getLocalStorage, getUniqueValues, getUniqueValuesByProperty, getValueByPath, groupBy, inicializarVariablesSessionStorage, isEmail, isProduction, jwtToken, jwtTokenData, jwtTokenExpiracion, jwtTokenExpiracionFaltante, localStorageKeys, markAsTouchedWithoutEmitEvent, maskEmail, mensajeAlerta, mensajeConfirmacion, mensajeTimer, mensajeToast, mensajesDeError, mensajesErrorFormControl, mostrarValorEnBusqueda, nestGroupsBy, numberToWords, objectPropertiesBoolean, objectPropertiesToType, obtenerHostDesdeUrl, obtenerMimeType, obtenerUltimoOrden, ordenarArray, ordenarPorPropiedad, ordenarPorPropiedades, roundToDecimal, sanitizarNombreArchivo, seleccionarTextoInput, setCambiarPwd, setControlDesdeLista, setJwtTokenData, setLocalStorage, setProductionMode, sumarObjetos, sumarPropiedades, tipoValorFuncion, toFormData, transformarFechasPorNombreDeCampo, verificarRUC, zeroFill };
2352
+ export { AutocompleteMatchValidatorDirective, DataEnListaPipe, DataModel, DateDiffStringPipe, FiltroPipe, FormControlIsRequiredPipe, JsonParsePipe, JvsAutocompleteDirective, JvsDisplayWithPipe, NoSanitizePipe, TipoValorFuncionPipe, ZeroFillPipe, b64Decode, b64Encode, buscarPorCampo, changeSelect, changeSelectApi, changeSelectData, changeSelectDataApi, changeSelectReformateado, convertirBytes, dataEnLista, dateDiffString, decodeBase64Object, decodeBase64String, decodeBase64ToBlob, deepClone, deepMerge, delLocalStorage, desencriptar, devError, devGroup, devGroupEnd, devLog, devTable, devTime, devTimeEnd, devWarn, downLoadFileStream, eliminarColumnaPorIndex, eliminarDuplicados, eliminarElementos, encodeBase64File, encodeBase64Object, encodeBase64String, encriptar, esNumero, esPromise, establecerQuitarRequired, extraerDominio, filtrarDatosLocal, formControlIsRequired, formatearFecha, formatearFechaCadena, formatearFechaFormato, generateRandomString, getBrowserName, getCambiarPwd, getDataArchivoFromPath, getFormValidationErrors, getLocalStorage, getUniqueValues, getUniqueValuesByProperty, getValueByPath, groupBy, inicializarVariablesSessionStorage, isEmail, isProduction, jwtToken, jwtTokenData, jwtTokenExpiracion, jwtTokenExpiracionFaltante, localStorageKeys, markAsTouchedWithoutEmitEvent, maskEmail, mensajeAlerta, mensajeConfirmacion, mensajeTimer, mensajeToast, mensajesDeError, mensajesErrorFormControl, mostrarValorEnBusqueda, nestGroupsBy, numberToWords, objectPropertiesBoolean, objectPropertiesToType, obtenerHostDesdeUrl, obtenerMimeType, obtenerUltimoOrden, ordenarArray, ordenarPorPropiedad, ordenarPorPropiedades, roundToDecimal, sanitizarNombreArchivo, seleccionarTextoInput, setCambiarPwd, setControlDesdeLista, setJwtTokenData, setLocalStorage, setProductionMode, sumarObjetos, sumarPropiedades, tipoValorFuncion, toFormData, transformarFechasPorNombreDeCampo, verificarRUC, zeroFill };
2124
2353
  //# sourceMappingURL=jvsoft-utils.mjs.map