function fieldNameFromId(id, prefix = "ipt") { if (!id) return ""; return id.startsWith(prefix) ? id.slice(prefix.length).toLowerCase() : id.toLowerCase(); } function formToFormData(form, opts = {}) { const { prefix = "ipt", idField = "iptId", exclude = [], multiSeparator = ",", } = opts; const fd = new FormData(); const frm = form.jquery ? form[0] : form; // Sólo controles de formulario reales const controls = frm.querySelectorAll("input, select, textarea"); for (const el of controls) { const type = (el.type || "").toLowerCase(); const id = el.id || ""; // descartar botones y derivados if (["button", "submit", "reset", "image"].includes(type)) continue; // descartar explícitos if (exclude.includes(id)) continue; // no incluir el campo id (se maneja aparte) if (id === idField) continue; // si no tiene id ni name, no sirve if (!id && !el.name) continue; const campo = fieldNameFromId(id || el.name, prefix); if (type === "radio") { if (el.checked) fd.append(campo, el.value); continue; } if (type === "checkbox") { fd.append(campo, el.checked ? 1 : 0); continue; } if (type === "select-multiple") { const values = Array.from(el.selectedOptions) .map((o) => o.value) .join(multiSeparator); fd.append(campo, values); continue; } if (type === "file") { if (el.files.length > 0) { if (el.multiple) for (const f of el.files) fd.append(campo + "[]", f); else fd.append(campo, el.files[0]); } else { fd.append(campo, ""); } continue; } // default: text, number, date, textarea, select-one, etc. fd.append(campo, el.value); } return fd; } function buildPayload(form, idField = "iptId") { const fd = formToFormData(form, { idField }); const idVal = document.getElementById(idField)?.value || ""; fd.append("accion", idVal === "" ? "NUEVO" : "EDITAR"); if (idVal !== "") fd.append("id", idVal); return fd; }