academy/js/cargar_datos.js

136 lines
3.9 KiB
JavaScript

function fillFormFromData($form, data) {
// ---- helpers ----
const normalize = (v) =>
v == null ? "" : typeof v === "string" ? v.trim() : v;
const toArray = (v) => {
if (Array.isArray(v)) return v;
if (!v) return [];
return String(v)
.split(",")
.map((x) => x.trim())
.filter(Boolean);
};
const ensureOption = ($select, value) => {
if (value === "" || value == null) return;
const exists = $select.find(`option[value="${value}"]`).length > 0;
if (!exists) $select.append(new Option(value, value));
};
// Convierte "22:00:00.0000000" -> "22:00" (también maneja "HH:MM:SS" y "HH:MM")
const toTimeValue = (v) => {
if (!v) return "";
const s = String(v).trim();
const m = s.match(/^(\d{1,2}):(\d{2})(?::\d{2}(?:\.\d+)?)?$/);
if (m) return `${m[1].padStart(2, "0")}:${m[2]}`; // HH:MM
// fallback por si llega como fecha completa
const d = new Date(s);
if (!isNaN(d)) return d.toTimeString().slice(0, 5); // HH:MM
return "";
};
// ---- binding genérico ----
for (const [campo, rawValor] of Object.entries(data)) {
// Evitar índices numéricos de consultas SQL (0,1,2,...)
if (!isNaN(campo)) continue;
const valor = normalize(rawValor);
// Buscar por id iptXxx y si no, por name="campo"
const inputId = "#ipt" + campo.charAt(0).toUpperCase() + campo.slice(1);
let $el = $form.find(inputId);
if (!$el.length) $el = $form.find(`[name="${campo}"]`);
if (!$el.length) continue;
// Radios (varios inputs con el mismo name)
if ($el.length > 1 && $el.is(":radio")) {
$el
.prop("checked", false)
.filter((_, r) => $(r).val() == valor)
.prop("checked", true)
.trigger("change");
continue;
}
const $c = $el.eq(0);
// Checkbox
if ($c.is(":checkbox")) {
$c.prop("checked", valor == 1 || valor === true || valor === "1").trigger(
"change"
);
continue;
}
// MultiSelect (Syncfusion) detectado por clase .multiselect
if ($c.hasClass("multiselect")) {
// obtener instancia de ej2 sin alias globales
const host = $c.get(0);
const inst = host?.ej2_instances?.[0]; // ej.dropdowns.MultiSelect
if (inst) {
inst.value = toArray(valor);
inst.dataBind();
} else {
// si por algún motivo aún no está instanciado, al menos deja el valor en un data-attr
$c.attr("data-pending-value", toArray(valor).join(","));
}
continue;
}
// Select normal (incluido selectpicker)
if ($c.is("select")) {
const multiple = $c.prop("multiple");
if (multiple) {
const arr = toArray(valor);
arr.forEach((v) => ensureOption($c, v));
$c.val(arr);
} else {
ensureOption($c, valor);
$c.val(valor);
}
if ($c.hasClass("selectpicker")) $c.selectpicker("refresh");
$c.trigger("change");
continue;
}
// Input time: recorta a HH:MM
if ($c.is('input[type="time"]')) {
$c.val(toTimeValue(valor)).trigger("change");
continue;
}
if ($c.hasClass("richtexteditor")) {
// Buscar instancia RTE en el contenedor #editor
const host = document.querySelector("#editor");
const inst = host?.ej2_instances?.[0]; // instancia del RTE
if (
inst &&
inst.getModuleName &&
inst.getModuleName() === "richtexteditor"
) {
inst.value = valor || "";
inst.dataBind();
// También reflejar el valor en el textarea oculto para que FormData lo capture
$c.val(valor || "");
} else {
// Si aún no está montado el editor, guardo el valor pendiente
$c.attr("data-pending-rte", valor || "");
}
continue;
}
// Inputs/textarea genéricos
if ($c.is("input, textarea")) {
$c.val(valor).trigger("change");
continue;
}
// Fallback para elementos de texto (spans/divs)
$c.text(valor);
}
}