136 lines
3.9 KiB
JavaScript
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);
|
|
}
|
|
}
|