UNPKG

material-dynamic-forms

Version:

¡Crea formularios dinámicos, potentes y configurables en Angular usando Material Design! 🚀

847 lines (842 loc) 88 kB
import * as i0 from '@angular/core'; import { Injectable, EventEmitter, Component, Inject, Input, Output, NgModule } from '@angular/core'; import * as i4 from '@angular/forms'; import { Validators, ReactiveFormsModule, FormsModule } from '@angular/forms'; import * as i2 from '@angular/common/http'; import { HttpParams } from '@angular/common/http'; import { ConfirmEventType } from 'primeng/api'; import { throwError } from 'rxjs'; import * as i1 from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import * as i10 from '@angular/material/core'; import { NativeDateAdapter, DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule, MatRippleModule } from '@angular/material/core'; import * as i3 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i5 from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox'; import * as i1$1 from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon'; import * as i7 from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button'; import * as i8 from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field'; import * as i9 from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select'; import * as i11 from '@angular/material/button-toggle'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import * as i12 from '@angular/material/input'; import { MatInputModule } from '@angular/material/input'; import * as i13 from '@angular/material/divider'; import { MatDividerModule } from '@angular/material/divider'; import * as i14 from '@angular/material/datepicker'; import { MatDatepickerModule } from '@angular/material/datepicker'; import * as i15 from 'primeng/multiselect'; import { MultiSelectModule } from 'primeng/multiselect'; import * as i16 from 'primeng/dropdown'; import { DropdownModule } from 'primeng/dropdown'; import * as i17 from 'primeng/autocomplete'; import { AutoCompleteModule } from 'primeng/autocomplete'; import { MatPaginatorModule } from '@angular/material/paginator'; import { MatTableModule } from '@angular/material/table'; import { MatSortModule } from '@angular/material/sort'; import { MatMenuModule } from '@angular/material/menu'; import { MatTooltipModule } from '@angular/material/tooltip'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatCardModule } from '@angular/material/card'; import { MatListModule } from '@angular/material/list'; import { MatSidenavModule } from '@angular/material/sidenav'; import { MatBadgeModule } from '@angular/material/badge'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatRadioModule } from '@angular/material/radio'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatTabsModule } from '@angular/material/tabs'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatGridListModule } from '@angular/material/grid-list'; import { MatChipsModule } from '@angular/material/chips'; import * as i2$1 from '@angular/platform-browser'; var eDataType; (function (eDataType) { eDataType[eDataType["input"] = 0] = "input"; eDataType[eDataType["select"] = 1] = "select"; eDataType[eDataType["date"] = 2] = "date"; eDataType[eDataType["select_search"] = 3] = "select_search"; eDataType[eDataType["range"] = 4] = "range"; eDataType[eDataType["button"] = 5] = "button"; eDataType[eDataType["checkbox"] = 6] = "checkbox"; eDataType[eDataType["dateMultiple"] = 7] = "dateMultiple"; eDataType[eDataType["tex_area"] = 8] = "tex_area"; eDataType[eDataType["button_toggle"] = 9] = "button_toggle"; eDataType[eDataType["select_chips"] = 10] = "select_chips"; eDataType[eDataType["select_autocomplete"] = 11] = "select_autocomplete"; eDataType[eDataType["input_autocomplete"] = 12] = "input_autocomplete"; })(eDataType || (eDataType = {})); var eControlType; (function (eControlType) { eControlType[eControlType["button"] = 0] = "button"; eControlType[eControlType["checkbox"] = 1] = "checkbox"; eControlType[eControlType["date"] = 2] = "date"; eControlType[eControlType["email"] = 3] = "email"; eControlType[eControlType["number"] = 4] = "number"; eControlType[eControlType["tel"] = 5] = "tel"; eControlType[eControlType["text"] = 6] = "text"; })(eControlType || (eControlType = {})); var eTypeMOdel; (function (eTypeMOdel) { eTypeMOdel[eTypeMOdel["boolean"] = 0] = "boolean"; eTypeMOdel[eTypeMOdel["number"] = 1] = "number"; })(eTypeMOdel || (eTypeMOdel = {})); function handleError(error) { let errorData = { status: 0, message: '', }; switch (error.status) { case 401 /* HttpStatusCode.Unauthorized */: removeItemStorage(); return throwError(error.error.message); case 400 /* HttpStatusCode.BadRequest */: case 409 /* HttpStatusCode.Conflict */: return throwError(error.error.message); case 402 /* HttpStatusCode.PaymentRequired */: errorData.status = error.status; errorData.message = error.error.data.mensaje; return throwError(errorData); case 422 /* HttpStatusCode.UnprocessableEntity */: return throwError(error.error); case 425 /* HttpStatusCode.TooEarly */: return throwError(error.error.message.errors); case 500 /* HttpStatusCode.InternalServerError */: return throwError(error.error.previous.message); default: return throwError('Something bad happened; please try again later.'); } } function removeNullValuesFromQueryParams(params) { const paramsKeysAux = params.keys(); paramsKeysAux.forEach((key) => { const value = params.get(key); if (value === null || value === undefined || value === '' || value === 'undefined') { params['map'].delete(key); } }); return params; } const FunctionRejectData = (type, _messageService) => { switch (type) { case ConfirmEventType.REJECT: _messageService.add({ severity: 'error', summary: 'Rechazada', detail: 'Rechazada la acción', }); break; case ConfirmEventType.CANCEL: _messageService.add({ severity: 'warn', summary: 'Cancelado', detail: 'Cancelada la acción', }); break; } }; function filterObjectKeys(obj, keysToKeep) { const newObj = {}; keysToKeep.forEach((key) => { if (key in obj) { newObj[key] = obj[key]; } }); return newObj; } function getValueFromProperty(row, property) { if (!row || !property) { return undefined; } const properties = property.split('.'); // Itera sobre las propiedades para acceder al valor final let value = row; for (const prop of properties) { value = value[prop]; if (value === undefined) { return undefined; } } return value; } function removeItemStorage() { localStorage.removeItem('token'); localStorage.removeItem('refresh_token'); localStorage.removeItem('session_id'); localStorage.removeItem('remember'); } const transformToObject = (objectSelect) => { return { id: Number(objectSelect.key), nombre: objectSelect.value, }; }; class DynamicFormService { constructor(fb, http) { this.fb = fb; this.http = http; this.baseUrl = ''; // Agregamos esta variable para almacenar los valores externos this.externalDependenciesValues = {}; // Declarar formGroupControls como propiedad this.formGroupControls = {}; // Variable para manejar el modo de edición this.isEditMode = false; this.isReadonly = false; // Add readonly flag this.rangeValidator = (group) => { var _a, _b; const desde = Number((_a = group.get('desde')) === null || _a === void 0 ? void 0 : _a.value); const hasta = Number((_b = group.get('hasta')) === null || _b === void 0 ? void 0 : _b.value); return desde <= hasta ? null : { rangeError: true }; }; } setBaseUrl(url) { this.baseUrl = url; } // Método para establecer el modo de edición setEditMode(isEdit) { this.isEditMode = isEdit; } // Add method to set readonly setReadonly(isReadonly) { this.isReadonly = isReadonly; } // Permite setear/actualizar los valores externos desde el componente setExternalDependenciesValues(values) { this.externalDependenciesValues = Object.assign(Object.assign({}, this.externalDependenciesValues), values); } removeExternalDependency(key) { if (this.externalDependenciesValues.hasOwnProperty(key)) { delete this.externalDependenciesValues[key]; } } functionInitComponent(fieldGroupsDynamicForm, form) { this.formGroupControls = {}; let isRangeValidator = false; const initializeControl = (field) => { const initialValue = field.value !== undefined ? field.value : field.type === eDataType.select_chips ? [] : ''; const validators = this.isReadonly ? [] : field.validation || []; const isDisabled = this.isReadonly || !!field.dependency || field.disabled; return this.fb.control({ value: initialValue, disabled: isDisabled }, validators); }; const handleDependenciesValue = (field, control) => { if (!field.valueDependency && !field.valueExcludeDependency) { return; } const updateField = () => { var _a, _b; const depValue = field.valueDependency ? this.formGroupControls[field.valueDependency.dependency] && this.formGroupControls[field.valueDependency.dependency].value : field.valueExcludeDependency ? this.formGroupControls[field.valueExcludeDependency.dependency] && this.formGroupControls[field.valueExcludeDependency.dependency] .value : undefined; const valueComparar = field.valueDependency ? field.valueDependency.valueDep : field.valueExcludeDependency ? field.valueExcludeDependency.valueDep : undefined; if (field.valueDependency && depValue === valueComparar) { control.enable(); control.clearValidators(); control.setValidators((_a = field.valueDependency.validation) !== null && _a !== void 0 ? _a : []); control.updateValueAndValidity(); } else if (field.valueExcludeDependency && depValue !== valueComparar) { control.enable(); control.clearValidators(); control.setValidators((_b = field.valueExcludeDependency.validation) !== null && _b !== void 0 ? _b : []); control.updateValueAndValidity(); } else { control.disable(); control.reset(); control.clearValidators(); control.updateValueAndValidity(); } }; if (field.valueDependency) { this.formGroupControls[field.valueDependency.dependency].valueChanges.subscribe(updateField); } else if (field.valueExcludeDependency) { this.formGroupControls[field.valueExcludeDependency.dependency].valueChanges.subscribe(updateField); } updateField(); }; const handleDependencies = (field, control) => { if (!field.dependency) { return; } const dependencyFields = field.dependency.split(','); dependencyFields.forEach((depField) => { if (!this.formGroupControls[depField]) { this.formGroupControls[depField] = this.fb.control('', Validators.required); } }); const updateField = () => { if ((field.valueDependency || field.valueExcludeDependency) && control.disabled) { return; } const allDependenciesFilled = dependencyFields.every((depField) => { var _a; return this.formGroupControls[depField] && ((_a = this.formGroupControls[depField]) === null || _a === void 0 ? void 0 : _a.value); }); if (allDependenciesFilled) { const dependencyValue = this.formGroupControls[dependencyFields[0]].value; if (!field.valueDependency && !field.valueExcludeDependency && field.disabled) { control.disable(); } else { control.enable(); } if (!this.isEditMode) control.reset(); // Verificar si hay dependencias externas const hasExternalDeps = field.externalDependencies && field.externalDependencies.length > 0; // Aquí se unifica la lógica de obtención de datos if (field.apiUrl && dependencyValue) { this.fetchOptions(field, dependencyValue, hasExternalDeps); } } else { control.reset(); field.options = []; if (!field.valueDependency && !field.valueExcludeDependency) { control.disable(); } } }; dependencyFields.forEach((depField) => { this.formGroupControls[depField].valueChanges.subscribe(updateField); }); updateField(); }; const handleDynamicDateConstraints = (field, control) => { if (!field.dateDependency || (!field.minDateFn && !field.maxDateFn)) { return; } const dependencyField = this.formGroupControls[field.dateDependency]; if (!dependencyField) { console.error(`El campo de dependencia ${field.dateDependency} no existe.`); return; } const updateConstraints = () => { const dependencyValue = dependencyField.value ? new Date(dependencyField.value) : null; if (dependencyValue) { // Asegurarse de que la hora sea 00:00:00 dependencyValue.setHours(0, 0, 0, 0); } if (field.minDateFn && dependencyValue) { const calculatedMinDate = field.minDateFn(dependencyValue); field.minDate = calculatedMinDate; control.setValidators([ ...(control.validator ? [control.validator] : []), Validators.min(calculatedMinDate.getTime()), ]); } if (field.maxDateFn && dependencyValue) { const calculatedMaxDate = field.maxDateFn(dependencyValue); field.maxDate = calculatedMaxDate; control.setValidators([ ...(control.validator ? [control.validator] : []), Validators.max(calculatedMaxDate.getTime()), ]); } control.updateValueAndValidity(); }; dependencyField.valueChanges.subscribe(updateConstraints); updateConstraints(); // Aplicar al inicializar // Forzar una actualización manual del valor del campo dependiente setTimeout(() => { dependencyField.updateValueAndValidity(); }, 0); }; fieldGroupsDynamicForm.forEach((group) => { var _a; group.fields.forEach((field) => { if (field.visible) { // Inicializar control const control = initializeControl(field); // Agregar control al objeto de controles if (field.name) this.formGroupControls[field.name] = control; // Agregar opciones al campo select sin dependencias if (field.apiUrl && !field.urlParamDependency && !field.urlQueryParam && !field.urlEndParam) { this.fetchOptions(field, null, false); } if (!this.isReadonly) { // Manejar dependencias de values de campos internas if (field.valueDependency || field.valueExcludeDependency) handleDependenciesValue(field, control); // Manejar dependencias de campos if (field.dependency) handleDependencies(field, control); // Manejar dependencias de fechas if (field.type === eDataType.date) handleDynamicDateConstraints(field, control); } } }); isRangeValidator = (_a = group.isRangeValidator) !== null && _a !== void 0 ? _a : false; }); form = this.fb.group(this.formGroupControls); if (isRangeValidator) form.setValidators(this.rangeValidator); if (this.isEditMode) { this.markControlsAsTouched(form); } if (this.isReadonly) { form.disable(); // Disable the entire form if readonly } return form; } markControlsAsTouched(form) { Object.keys(form.controls).forEach((key) => { const control = form.get(key); if (control) { control.markAsTouched(); control.updateValueAndValidity(); // Actualiza los errores y validaciones } }); } handleExternalDependenciesService(field, control) { if (!control) { console.warn(`Control no encontrado para el campo ${field.name}`); return () => { }; } const checkDependencies = () => { var _a; // 1) Verificar dependencias externas const depsExtOk = (_a = field.externalDependencies) === null || _a === void 0 ? void 0 : _a.every((dep) => { var _a; return ((_a = this.externalDependenciesValues) === null || _a === void 0 ? void 0 : _a[dep]) !== undefined; }); // 2) Verificar dependencias de formulario (field.dependency) let depsFormOk = true; if (field.dependency) { const dependencyFields = field.dependency.split(','); // Chequea que todos esos campos tengan algún valor depsFormOk = dependencyFields.every((depField) => { var _a; return !!((_a = this.formGroupControls[depField]) === null || _a === void 0 ? void 0 : _a.value); }); } // Si todo está OK, habilitar campo y llamar a la API if (depsExtOk && depsFormOk) { control.enable(); if (field.apiUrl) { // Verificar si hay dependencias externas const hasExternalDeps = field.externalDependencies && field.externalDependencies.length > 0; // fetchOptions con "useExternalDeps = true" si hay dependencias externas this.fetchOptions(field, undefined, hasExternalDeps); } } else if (!this.isEditMode || !control.value) { // Si no está en modo edición o el control no tiene valor, deshabilita control.disable(); control.reset(); field.options = []; } // En modo edición y tiene valor, no hacer nada para mantener el valor }; // Ejecuta inicialmente checkDependencies(); // Retorna la función para que el componente la invoque cuando cambien las dependencias return checkDependencies; } functionGetFormValue(form, fieldGroupsDynamicForm) { let dataFilterSend = {}; fieldGroupsDynamicForm.forEach((group) => { group.fields.forEach((fieldDynamicForm) => { var _a; const control = form.get(fieldDynamicForm.name); if (control) { if (control.value !== '' && control.value !== null) { fieldDynamicForm.active = true; switch (fieldDynamicForm.type) { case eDataType.select: fieldDynamicForm.value = control.value; if (control.value === -1) { fieldDynamicForm.options = [ { key: -1, value: 'TODOS' }, ...fieldDynamicForm.options, ]; } fieldDynamicForm.selectedOption = (_a = fieldDynamicForm.options) === null || _a === void 0 ? void 0 : _a.find((option) => option.key === control.value); fieldDynamicForm.filterParam ? (dataFilterSend[fieldDynamicForm.filterParam] = fieldDynamicForm.selectedOption ? fieldDynamicForm.selectedOption['key'] : null) : (dataFilterSend[fieldDynamicForm.name] = fieldDynamicForm.selectedOption ? transformToObject(fieldDynamicForm.selectedOption) : null); break; case eDataType.date: fieldDynamicForm.value = control.value || null; dataFilterSend[fieldDynamicForm.name] = fieldDynamicForm.value; break; default: fieldDynamicForm.value = fieldDynamicForm.typeModel === eTypeMOdel.number ? Number(control.value) : control.value; //fieldDynamicForm.value = control.value; dataFilterSend[fieldDynamicForm.name] = fieldDynamicForm.value; break; } } else { fieldDynamicForm.active = false; fieldDynamicForm.value = null; dataFilterSend[fieldDynamicForm.name] = null; } } }); }); return dataFilterSend; } buildUrlAndParams(field, dependencyValue, useExternalDeps = false) { let url = `${this.baseUrl}${field.apiUrl}`; let params = new HttpParams(); // 1. urlParamDependency (ej: /api/{id}) if (field.urlParamDependency && dependencyValue) { url = url.replace(/\{.*?\}/g, dependencyValue); } // 2. urlQueryParam (ej: ?depField=value) else if (field.urlQueryParam && field.dependency) { const dependencyFields = field.dependency.split(','); dependencyFields.forEach((depField) => { params = params.set(depField, this.formGroupControls[depField].value); }); } // 3. urlEndParam (ej: /api/id) else if (field.urlEndParam && dependencyValue) { url = `${url}/${dependencyValue}`; } // 4. Agregar dependencias externas si se indica if (useExternalDeps && field.externalDependencies) { field.externalDependencies.forEach((dep) => { if (this.externalDependenciesValues[dep] !== undefined) { params = params.append(dep, this.externalDependenciesValues[dep]); } }); } return { url, params }; } fetchOptions(field, dependencyValue, useExternalDeps = false) { if (!field.apiUrl) { return; } const { url, params } = this.buildUrlAndParams(field, dependencyValue, useExternalDeps); this.http.get(url, { params }).subscribe((res) => { var _a; field.options = field.subscribeMap ? field.subscribeMap(res).map((item) => ({ key: item.id, value: field.valueTOShow ? getValueFromProperty(item, field.valueTOShow) : item.nombre || item.name, data: item.data, })) : res.data.map((item) => ({ key: item.id, value: field.valueTOShow ? item[field.valueTOShow] : item.nombre || item.name, data: item, })); (_a = field.options) === null || _a === void 0 ? void 0 : _a.sort((a, b) => (a.value || '').localeCompare(b.value || '')); }); } } DynamicFormService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DynamicFormService, deps: [{ token: i4.FormBuilder }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); DynamicFormService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DynamicFormService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DynamicFormService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i4.FormBuilder }, { type: i2.HttpClient }]; } }); const CONST_TYPE_STRING = 'string'; const CONST_TYPE_NUMBER = 'number'; const CONST_TYPE_NUMERIC = 'numeric'; const CONST_TYPE_LONG = 'long'; const CONST_DISPLAY_FORMAT_INPUT = 'input'; const CONST_DISPLAY_FORMAT_INPUTMONTH = 'inputMonth'; class AppDateAdapter extends NativeDateAdapter { parse(value) { if (typeof value === CONST_TYPE_STRING && value.indexOf('/') > -1) { const str = value.split('/'); const year = Number(str[2]); const month = Number(str[1]) - 1; const date = Number(str[0]); return new Date(year, month, date); } const timestamp = typeof value === CONST_TYPE_NUMBER ? value : Date.parse(value); return isNaN(timestamp) ? null : new Date(timestamp); } format(date, displayFormat) { if (displayFormat === CONST_DISPLAY_FORMAT_INPUT) { let day = date.getDate(); let month = date.getMonth() + 1; let year = date.getFullYear(); return this._to2digit(day) + '/' + this._to2digit(month) + '/' + year; } else if (displayFormat === CONST_DISPLAY_FORMAT_INPUTMONTH) { let month = date.getMonth() + 1; let year = date.getFullYear(); return this._to2digit(month) + '/' + year; } else { return date.toDateString(); } } _to2digit(n) { return ('00' + n).slice(-2); } } const APP_DATE_FORMATS = { parse: { dateInput: { month: 'short', year: CONST_TYPE_NUMERIC, day: CONST_TYPE_NUMERIC }, }, display: { dateInput: CONST_DISPLAY_FORMAT_INPUT, monthYearLabel: CONST_DISPLAY_FORMAT_INPUTMONTH, dateA11yLabel: { year: CONST_TYPE_NUMERIC, month: CONST_TYPE_LONG, day: CONST_TYPE_NUMERIC }, monthYearA11yLabel: { year: CONST_TYPE_NUMERIC, month: CONST_TYPE_LONG }, }, }; class DynamicFormComponent { constructor(data, modal, dynamicFormService) { this.data = data; this.modal = modal; this.dynamicFormService = dynamicFormService; this.isModal = false; this.isEdit = false; this.isReadonlyForm = false; this.changeValueSelected = new EventEmitter(); this.formValidityChange = new EventEmitter(); this.externalDependenciesValuesChanged = new EventEmitter(); this.eDataType = eDataType; this.title = ''; this.titleButton = 'Guardar'; this.selectedOption = null; } ngOnInit() { this.inizializarForm(); } ngOnDestroy() { this.form.reset(); } ngOnChanges(changes) { // Detecta si el valor de resetFormTrigger cambia if (changes['resetFormTrigger'] && changes['resetFormTrigger'].currentValue) { this.form.reset(); // Resetea el formulario } // Detecta si el valor de baseUrl cambia if (changes['baseUrl'] && changes['baseUrl'].currentValue) { this.dynamicFormService.setBaseUrl(this.baseUrl); } // Detecta si el valor de isEdit cambia if (changes['isEdit'] && changes['isEdit'].currentValue) { this.dynamicFormService.setEditMode(this.isEdit); } } inizializarForm() { var _a; if (this.isReadonlyForm) { this.dynamicFormService.setReadonly(true); } // En el caso que se esta utilizando un formulario desde una modal MatDialog if ((_a = this.data) === null || _a === void 0 ? void 0 : _a.dataForm) { this.fieldGroups = this.data.dataForm.fieldGroups; this.isModal = true; this.title = this.data.title; this.titleButton = this.data.dataForm.titleButtonAcceptForm; if (this.data.dataForm.baseUrl) { this.dynamicFormService.setBaseUrl(this.data.dataForm.baseUrl); this.baseUrl = this.data.dataForm.baseUrl; } if (this.data.dataForm.form) { this.form = this.data.dataForm.form; } if (this.data.dataForm.edit) { this.isEdit = this.data.dataForm.edit; this.dynamicFormService.setEditMode(this.data.dataForm.edit); } } // Inicializa el formulario if (this.fieldGroups) { this.form = this.dynamicFormService.functionInitComponent(this.fieldGroups, this.form); // Manejar campos con dependencias externas this.fieldGroups.forEach((group) => { group.fields.forEach((field) => { if (field.externalDependencies) { this.handleExternalDependencies(field); } }); }); } // Emito la validacion actual del form this.formValidityChange.emit(this.form.valid); // Escucha los cambios de estado del formulario y emite el resultado this.form.statusChanges.subscribe(() => { this.formValidityChange.emit(this.form.valid); }); } /** * Método para manejar dependencias externas. */ handleExternalDependencies(field) { const control = this.form.get(field.name); // Llamamos al servicio const checkDependencies = this.dynamicFormService.handleExternalDependenciesService(field, control); // Suscribimos el EventEmitter para volver a verificar las dependencias // cuando cambien los valores externos this.externalDependenciesValuesChanged.subscribe(() => { checkDependencies === null || checkDependencies === void 0 ? void 0 : checkDependencies(); }); } // Método para actualizar las dependencias externas updateExternalDependencies(values) { // Actualizas la variable en el servicio this.dynamicFormService.setExternalDependenciesValues(values); // Emite el evento si deseas que otros sitios en el componente reaccionen this.externalDependenciesValuesChanged.emit(); } // Método para actualizar el valor de un campo del formulario updateFormField(fieldName, value) { if (this.form && this.form.controls[fieldName]) { this.form.controls[fieldName].setValue(value); } } /** * Función pública para deshabilitar un campo específico * @param fieldName Nombre del campo a deshabilitar */ disableField(fieldName) { const control = this.form.get(fieldName); if (control) { control.disable(); } else { console.warn(`El campo con nombre "${fieldName}" no existe en el formulario.`); } } /** * Función pública para habilitar un campo específico * @param fieldName Nombre del campo a habilitar */ enableField(fieldName) { const control = this.form.get(fieldName); if (control) { control.enable(); } else { console.warn(`El campo con nombre "${fieldName}" no existe en el formulario.`); } } removeExternalDependency(key) { this.dynamicFormService.removeExternalDependency(key); this.externalDependenciesValuesChanged.emit(); } refreshDependentFields() { // Emit the event to refresh dependencies this.externalDependenciesValuesChanged.emit(); } simulateFieldChange(fieldName) { const control = this.form.get(fieldName); if (control) { const currentValue = control.value; control.setValue(currentValue); } } getFormFieldValue(fieldName) { var _a; return (_a = this.form.get(fieldName)) === null || _a === void 0 ? void 0 : _a.value; } onSubmit() { let listadoFormGet = this.dynamicFormService.functionGetFormValue(this.form, this.fieldGroups); this.modal.close(listadoFormGet); } emitEvent(nameForm, event) { var _a; let value; value = (_a = this.form.get(nameForm.name)) === null || _a === void 0 ? void 0 : _a.value; if (event) { value = event.value; } this.changeValueSelected.emit({ form: nameForm, value: value }); } getForm() { return this.form; } getErrorMessage(fieldName) { const control = this.form.get(fieldName); if (control === null || control === void 0 ? void 0 : control.hasError('required')) { return 'Este campo es obligatorio'; } if (control === null || control === void 0 ? void 0 : control.hasError('min')) { return `El valor debe ser mayor o igual a ${control.getError('min').min}`; } if (control === null || control === void 0 ? void 0 : control.hasError('max')) { return `El valor debe ser menor o igual a ${control.getError('max').max}`; } if (control === null || control === void 0 ? void 0 : control.hasError('email')) { return 'Debe ser un correo electrónico válido'; } if (control === null || control === void 0 ? void 0 : control.hasError('pattern')) { return 'El formato no es válido'; } if (control === null || control === void 0 ? void 0 : control.hasError('minlength')) { return `Debe tener al menos ${control.getError('minlength').requiredLength} caracteres`; } if (control === null || control === void 0 ? void 0 : control.hasError('maxlength')) { return `Debe tener como máximo ${control.getError('maxlength').requiredLength} caracteres`; } // Agrega más validaciones según sea necesario return null; } getGridColumns(columnCount) { return `repeat(${columnCount || 1}, 1fr)`; } getColSpanClass(colspan) { return colspan ? `col-span-${colspan}` : 'col-span-1'; } } DynamicFormComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: DynamicFormComponent, deps: [{ token: MAT_DIALOG_DATA }, { token: i1.MatDialogRef }, { token: DynamicFormService }], target: i0.ɵɵFactoryTarget.Component }); DynamicFormComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: DynamicFormComponent, selector: "lib-dynamic-form", inputs: { fieldGroups: "fieldGroups", isModal: "isModal", baseUrl: "baseUrl", resetFormTrigger: "resetFormTrigger", isEdit: "isEdit", isReadonlyForm: "isReadonlyForm" }, outputs: { changeValueSelected: "changeValueSelected", formValidityChange: "formValidityChange", externalDependenciesValuesChanged: "externalDependenciesValuesChanged" }, providers: [ DynamicFormService, { provide: DateAdapter, useClass: AppDateAdapter, }, { provide: MAT_DATE_FORMATS, useValue: APP_DATE_FORMATS, }, { provide: MAT_DATE_LOCALE, useValue: 'es-ES', }, ], usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\" class=\"my-2\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"flex items-center\" mat-dialog-title *ngIf=\"isModal\">\r\n <h2 class=\"headline m-0 flex-auto\">{{ title }}</h2>\r\n </div>\r\n <mat-divider *ngIf=\"isModal\" class=\"-mx-6 text-border\"></mat-divider>\r\n\r\n <mat-dialog-content class=\"flex flex-col\">\r\n <div *ngFor=\"let groups of fieldGroups\">\r\n <div mat-dialog-title *ngIf=\"groups.title\">\r\n <h6 class=\"title-group m-0 flex-auto\">{{ groups.title }}</h6>\r\n </div>\r\n <div\r\n class=\"grid-container\"\r\n [style.gridTemplateColumns]=\"getGridColumns(groups.countColumns || 1)\"\r\n >\r\n <div\r\n *ngFor=\"let field of groups.fields\"\r\n [class]=\"getColSpanClass(field.colspan)\"\r\n >\r\n <div [ngSwitch]=\"field.type\" *ngIf=\"field.visible\">\r\n <!-- INPUT -->\r\n <mat-form-field\r\n *ngSwitchCase=\"eDataType.input\"\r\n appearance=\"outline\"\r\n class=\"w-full\"\r\n [attr.style]=\"\r\n field.background\r\n ? '--dynamic-background-color: ' + field.background\r\n : 'transparent'\r\n \"\r\n >\r\n <mat-label>{{ field.label }}</mat-label>\r\n <input\r\n [type]=\"field.controlType!\"\r\n matInput\r\n [placeholder]=\"field.placeholder!\"\r\n [formControlName]=\"field.name!\"\r\n [value]=\"field.value ? field.value : ''\"\r\n (blur)=\"emitEvent(field)\"\r\n />\r\n <mat-icon\r\n [svgIcon]=\"field.icon!\"\r\n class=\"icon-sm\"\r\n matSuffix\r\n ></mat-icon>\r\n\r\n <!-- MENSAJES DE ERROR -->\r\n <mat-error\r\n *ngIf=\"\r\n form.controls[field.name]?.invalid &&\r\n (form.controls[field.name]?.touched ||\r\n form.controls[field.name]?.dirty)\r\n \"\r\n >\r\n {{ getErrorMessage(field.name) }}\r\n </mat-error>\r\n </mat-form-field>\r\n\r\n <!-- SELECT -->\r\n <mat-form-field\r\n *ngSwitchCase=\"eDataType.select\"\r\n appearance=\"outline\"\r\n class=\"w-full\"\r\n [attr.style]=\"\r\n field.background\r\n ? '--dynamic-background-color: ' + field.background\r\n : 'transparent'\r\n \"\r\n >\r\n <mat-label>{{ field.label }}</mat-label>\r\n <mat-select\r\n [formControlName]=\"field.name!\"\r\n (selectionChange)=\"emitEvent(field, $event)\"\r\n >\r\n <mat-option *ngIf=\"field.allOption\" [value]=\"-1\"\r\n >TODOS</mat-option\r\n >\r\n <mat-option\r\n *ngFor=\"let option of field.options\"\r\n [value]=\"option.key\"\r\n >\r\n {{ option.value }}\r\n </mat-option>\r\n </mat-select>\r\n\r\n <!-- MENSAJES DE ERROR -->\r\n <mat-error\r\n *ngIf=\"\r\n form.controls[field.name]?.invalid &&\r\n (form.controls[field.name]?.touched ||\r\n form.controls[field.name]?.dirty)\r\n \"\r\n >\r\n {{ getErrorMessage(field.name) }}\r\n </mat-error>\r\n </mat-form-field>\r\n\r\n <!-- SELECT WITH AUTOCOMPLETE -->\r\n <div\r\n *ngSwitchCase=\"eDataType.select_autocomplete\"\r\n style=\"margin-bottom: 15px\"\r\n >\r\n <h2 *ngIf=\"field.label\" class=\"label-custom\">\r\n {{ field.label }}\r\n </h2>\r\n <p-dropdown\r\n [options]=\"field.options!\"\r\n [formControlName]=\"field.name\"\r\n [filter]=\"true\"\r\n [showClear]=\"true\"\r\n [placeholder]=\"field.placeholder || 'Seleccione'\"\r\n (onChange)=\"emitEvent(field, $event)\"\r\n optionLabel=\"value\"\r\n optionValue=\"key\"\r\n appendTo=\"body\"\r\n filterBy=\"value\"\r\n >\r\n </p-dropdown>\r\n <!-- MENSAJES DE ERROR -->\r\n <mat-error\r\n *ngIf=\"\r\n form.controls[field.name]?.invalid &&\r\n (form.controls[field.name]?.touched ||\r\n form.controls[field.name]?.dirty)\r\n \"\r\n >\r\n {{ getErrorMessage(field.name) }}\r\n </mat-error>\r\n </div>\r\n\r\n <!-- INPUT AUTOCOMPLETE -->\r\n <div\r\n *ngSwitchCase=\"eDataType.input_autocomplete\"\r\n style=\"margin-bottom: 15px\"\r\n >\r\n <h2 *ngIf=\"field.label\" class=\"label-custom\">\r\n {{ field.label }}\r\n </h2>\r\n <span class=\"p-input-icon-right w-full mr-2\">\r\n <i class=\"pi pi-search\"></i>\r\n <p-autoComplete\r\n [formControlName]=\"field.name\"\r\n [placeholder]=\"field.placeholder || ''\"\r\n [suggestions]=\"field.inputAutoComplete?.suggestions || []\"\r\n [showClear]=\"field.inputAutoComplete?.showClear || true\"\r\n (completeMethod)=\"\r\n field.inputAutoComplete?.onCompleteMethod($event)\r\n \"\r\n (onClear)=\"field.inputAutoComplete?.onClear($event)\"\r\n (onSelect)=\"field.inputAutoComplete?.onSelect($event)\"\r\n field=\"value\"\r\n optionValue=\"key\"\r\n styleClass=\"w-full\"\r\n inputStyleClass=\"w-full p-inputtext\"\r\n appendTo=\"body\"\r\n >\r\n </p-autoComplete>\r\n </span>\r\n <!-- MENSAJES DE ERROR -->\r\n <mat-error\r\n *ngIf=\"\r\n form.controls[field.name]?.invalid &&\r\n (form.controls[field.name]?.touched ||\r\n form.controls[field.name]?.dirty)\r\n \"\r\n >\r\n {{ getErrorMessage(field.name) }}\r\n </mat-error>\r\n </div>\r\n\r\n <!-- SELECT-CHIPS -->\r\n <div *ngSwitchCase=\"eDataType.select_chips\">\r\n <h2 class=\"label-custom\">{{ field.label }}</h2>\r\n <p-multiSelect\r\n [options]=\"field.options!\"\r\n [formControlName]=\"field.name\"\r\n [defaultLabel]=\"field.placeholder || ''\"\r\n (onChange)=\"emitEvent(field, $event)\"\r\n optionLabel=\"value\"\r\n optionValue=\"key\"\r\n display=\"chip\"\r\n appendTo=\"body\"\r\n ></p-multiSelect>\r\n <!-- MENSAJES DE ERROR -->\r\n <mat-error\r\n *ngIf=\"\r\n form.controls[field.name]?.invalid &&\r\n (form.controls[field.name]?.touched ||\r\n form.controls[field.name]?.dirty)\r\n \"\r\n >\r\n {{ getErrorMessage(field.name) }}\r\n </mat-error>\r\n </div>\r\n\r\n <!-- DATE -->\r\n <ng-container *ngSwitchCase=\"eDataType.date\">\r\n <ng-container\r\n *ngIf=\"!field.multiple; then singleDate; else rangeDate\"\r\n >\r\n </ng-container>\r\n </ng-container>\r\n\r\n <!-- DATE-SINGLE -->\r\n <ng-template #singleDate>\r\n <mat-form-field\r\n appearance=\"outline\"\r\n class=\"w-full\"\r\n [attr.style]=\"\r\n field.background\r\n ? '--dynamic-background-color: ' + field.background\r\n : 'transparent'\r\n \"\r\n >\r\n <mat-label style=\"font-size: 12px\">{{ field.label }}</mat-label>\r\n <input\r\n [matDatepicker]=\"datepickerRef\"\r\n [formControlName]=\"field.name!\"\r\n matInput\r\n (dateChange)=\"emitEvent(field, $event)\"\r\n [min]=\"field.minDate || null\"\r\n [max]=\"field.maxDate || null\"\r\n [matDatepickerFilter]=\"field.dateFilterFn!\"\r\n />\r\n <mat-datepicker-toggle\r\n [for]=\"datepickerRef\"\r\n class=\"block\"\r\n matSuffix\r\n ></mat-datepicker-toggle>\r\n <mat-datepicker\r\n #datepickerRef\r\n class=\"end-position\"\r\n ></mat-datepicker>\r\n\r\n <!-- MENSAJES DE ERROR -->\r\n <mat-error\r\n *ngIf=\"\r\n form.controls[field.name]?.invalid &&\r\n (form.controls[field.name]?.touched ||\r\n form.controls[field.name]?.dirty)\r\n \"\r\n >\r\n {{ getErrorMessage(field.name) }}\r\n </mat-error>\r\n </mat-form-field>\r\n </ng-template>\r\n\r\n <!-- DATE-RANGE -->\r\n <ng-template #rangeDate>\r\n <mat-form-field\r\n appearance=\"outline\"\r\n class=\"w-full\"\r\n [attr.style]=\"\r\n field.background\r\n ? '--dynamic-background-color: ' + field.background\r\n : 'transparent'\r\n \"\r\n >\r\n <mat-label>{{ field.label }}</mat-label>\r\n <mat-date-range-input [rangePicker]=\"picker\">\r\n <input\r\n matStartDate\r\n placeholder=\"Fecha Inicial\"\r\n [formControlName]=\"field.name + 'start'\"\r\n (dateChange)=\"emitEvent(field, $event)\"\r\n />\r\n <input\r\n matEndDate\r\n placeholder=\"Fecha Final\"\r\n [formControlName]=\"field.name + 'end'\"\r\n />\r\n </mat-date-range-input>\r\n\r\n <mat-datepicker-toggle