{"id":1624,"date":"2024-08-02T10:41:40","date_gmt":"2024-08-02T08:41:40","guid":{"rendered":"https:\/\/blog.sutilweb.eu\/?page_id=1624"},"modified":"2024-08-02T10:41:42","modified_gmt":"2024-08-02T08:41:42","slug":"004-envio-formulario-con-fetch-y-formsubmit","status":"publish","type":"page","link":"https:\/\/sutilweb.eu\/index.php\/lenguajes\/javascript\/javascript-practico\/17-ejercicios-con-ajax\/004-envio-formulario-con-fetch-y-formsubmit\/","title":{"rendered":"004. Env\u00edo Formulario con Fetch y FormSubmit"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A partir de este ejercicio comenzamos a trabajar con el <strong>API<\/strong> de <strong>FETCH<\/strong>. Para este ejercicio vamos a crear un archivo llamado <em>contact-form.html<\/em>, que va a tener la siguiente sintaxis.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\">Sintaxis de <em>contact-form.html<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n&nbsp; &lt;head&gt;\n&nbsp; &nbsp; &lt;meta charset=\"UTF-8\" \/&gt;\n&nbsp; &nbsp; &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" \/&gt;\n&nbsp; &nbsp; &lt;title&gt;Env\u00edo de formulario con Fetch y FormSubmit&lt;\/title&gt;\n&nbsp; &nbsp; &lt;style&gt;\n&nbsp; &nbsp; &nbsp; html {\n&nbsp; &nbsp; &nbsp; &nbsp; box-sizing: border-box;\n&nbsp; &nbsp; &nbsp; &nbsp; font-family: sans-serif;\n&nbsp; &nbsp; &nbsp; &nbsp; font-size: 16px;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; *,\n&nbsp; &nbsp; &nbsp; *::before,\n&nbsp; &nbsp; &nbsp; *::after {\n&nbsp; &nbsp; &nbsp; &nbsp; box-sizing: inherit;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; \/* **** ContactForm Validations **** *\/\n&nbsp; &nbsp; &nbsp; .contact-form {\n&nbsp; &nbsp; &nbsp; &nbsp; --form-ok-color: #4caf50;\n&nbsp; &nbsp; &nbsp; &nbsp; --form-error-color: #f44336;\n&nbsp; &nbsp; &nbsp; &nbsp; margin-left: auto;\n&nbsp; &nbsp; &nbsp; &nbsp; margin-right: auto;\n&nbsp; &nbsp; &nbsp; &nbsp; width: 80%;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form &gt; * {\n&nbsp; &nbsp; &nbsp; &nbsp; padding: 0.5rem;\n&nbsp; &nbsp; &nbsp; &nbsp; margin: 1rem auto;\n&nbsp; &nbsp; &nbsp; &nbsp; display: block;\n&nbsp; &nbsp; &nbsp; &nbsp; width: 100%;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form textarea {\n&nbsp; &nbsp; &nbsp; &nbsp; resize: none;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form legend,\n&nbsp; &nbsp; &nbsp; .contact-form-response {\n&nbsp; &nbsp; &nbsp; &nbsp; font-size: 1.5rem;\n&nbsp; &nbsp; &nbsp; &nbsp; font-weight: bold;\n&nbsp; &nbsp; &nbsp; &nbsp; text-align: center;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form input,\n&nbsp; &nbsp; &nbsp; .contact-form textarea {\n&nbsp; &nbsp; &nbsp; &nbsp; font-size: 1rem;\n&nbsp; &nbsp; &nbsp; &nbsp; font-family: sans-serif;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form input[type=\"submit\"] {\n&nbsp; &nbsp; &nbsp; &nbsp; width: 50%;\n&nbsp; &nbsp; &nbsp; &nbsp; font-weight: bold;\n&nbsp; &nbsp; &nbsp; &nbsp; cursor: pointer;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form *::placeholder {\n&nbsp; &nbsp; &nbsp; &nbsp; color: #000;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form [required]:valid {\n&nbsp; &nbsp; &nbsp; &nbsp; border: thin solid var(--form-ok-color);\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form [required]:invalid {\n&nbsp; &nbsp; &nbsp; &nbsp; border: thin solid var(--form-error-color);\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form-error {\n&nbsp; &nbsp; &nbsp; &nbsp; margin-top: -1rem;\n&nbsp; &nbsp; &nbsp; &nbsp; font-size: 80%;\n&nbsp; &nbsp; &nbsp; &nbsp; background-color: var(--form-error-color);\n&nbsp; &nbsp; &nbsp; &nbsp; color: #fff;\n&nbsp; &nbsp; &nbsp; &nbsp; transition: all 800ms ease;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form-error.is-active {\n&nbsp; &nbsp; &nbsp; &nbsp; display: block;\n&nbsp; &nbsp; &nbsp; &nbsp; animation: show-message 1s 1 normal 0s ease-out both;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .contact-form-loader {\n&nbsp; &nbsp; &nbsp; &nbsp; text-align: center;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; .none {\n&nbsp; &nbsp; &nbsp; &nbsp; display: none;\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; @keyframes show-message {\n&nbsp; &nbsp; &nbsp; &nbsp; 0% {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; visibility: hidden;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; opacity: 0;\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; 100% {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; visibility: visible;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; opacity: 1;\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &lt;\/style&gt;\n&nbsp; &lt;\/head&gt;\n\n&nbsp; &lt;body&gt;\n&nbsp; &nbsp; &lt;form class=\"contact-form\"&gt;\n&nbsp; &nbsp; &nbsp; &lt;legend&gt;Env\u00eda tus comentarios&lt;\/legend&gt;\n&nbsp; &nbsp; &nbsp; &lt;input\n&nbsp; &nbsp; &nbsp; &nbsp; type=\"text\"\n&nbsp; &nbsp; &nbsp; &nbsp; name=\"name\"\n&nbsp; &nbsp; &nbsp; &nbsp; placeholder=\"Escribe tu nombre\"\n&nbsp; &nbsp; &nbsp; &nbsp; title=\"Nombre s\u00f3lo acepta letras y espacios en blanco\"\n&nbsp; &nbsp; &nbsp; &nbsp; pattern=\"^[A-Za-z\u00d1\u00f1\u00c1\u00e1\u00c9\u00e9\u00cd\u00ed\u00d3\u00f3\u00da\u00fa\u00dc\u00fc\\s]+$\"\n&nbsp; &nbsp; &nbsp; &nbsp; required\n&nbsp; &nbsp; &nbsp; \/&gt;\n&nbsp; &nbsp; &nbsp; &lt;input\n&nbsp; &nbsp; &nbsp; &nbsp; type=\"email\"\n&nbsp; &nbsp; &nbsp; &nbsp; name=\"email\"\n&nbsp; &nbsp; &nbsp; &nbsp; placeholder=\"Escribe tu correo\"\n&nbsp; &nbsp; &nbsp; &nbsp; title=\"Email incorrecto\"\n&nbsp; &nbsp; &nbsp; &nbsp; pattern=\"^[a-z0-9]+(\\.[_a-z0-9]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,15})$\"\n&nbsp; &nbsp; &nbsp; &nbsp; required\n&nbsp; &nbsp; &nbsp; \/&gt;\n&nbsp; &nbsp; &nbsp; &lt;input\n&nbsp; &nbsp; &nbsp; &nbsp; type=\"text\"\n&nbsp; &nbsp; &nbsp; &nbsp; name=\"subject\"\n&nbsp; &nbsp; &nbsp; &nbsp; placeholder=\"Asunto a tratar\"\n&nbsp; &nbsp; &nbsp; &nbsp; title=\"El asunto es requerido\"\n&nbsp; &nbsp; &nbsp; &nbsp; required\n&nbsp; &nbsp; &nbsp; \/&gt;\n&nbsp; &nbsp; &nbsp; &lt;textarea\n&nbsp; &nbsp; &nbsp; &nbsp; name=\"comments\"\n&nbsp; &nbsp; &nbsp; &nbsp; cols=\"50\"\n&nbsp; &nbsp; &nbsp; &nbsp; rows=\"5\"\n&nbsp; &nbsp; &nbsp; &nbsp; placeholder=\"Escribe tus comentarios\"\n&nbsp; &nbsp; &nbsp; &nbsp; data-pattern=\"^.{1,255}$\"\n&nbsp; &nbsp; &nbsp; &nbsp; title=\"Tu comentario no debe sobrepasar los 255 caracteres\"\n&nbsp; &nbsp; &nbsp; &nbsp; required\n&nbsp; &nbsp; &nbsp; &gt;&lt;\/textarea&gt;\n&nbsp; &nbsp; &nbsp; &lt;input type=\"submit\" value=\"Enviar\" \/&gt;\n&nbsp; &nbsp; &nbsp; &lt;div class=\"contact-form-loader none\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;img src=\"loader.svg\" alt=\"Cargando\" \/&gt;\n&nbsp; &nbsp; &nbsp; &lt;\/div&gt;\n&nbsp; &nbsp; &nbsp; &lt;div class=\"contact-form-response none\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;p&gt;Los datos han sido enviados&lt;\/p&gt;\n&nbsp; &nbsp; &nbsp; &lt;\/div&gt;\n&nbsp; &nbsp; &lt;\/form&gt;\n\n&nbsp; &nbsp; &lt;script&gt;\n&nbsp; &nbsp; &nbsp; const d = document;\n\n&nbsp; &nbsp; &nbsp; function contactForm() {\n&nbsp; &nbsp; &nbsp; &nbsp; const $form = d.querySelector(\".contact-form\"),\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $inputs = d.querySelectorAll(\".contact-form [required]\");\n&nbsp; &nbsp; &nbsp; &nbsp; \/\/ console.log($imputs);\n&nbsp; &nbsp; &nbsp; &nbsp; $inputs.forEach((input) =&gt; {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const $span = d.createElement(\"span\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $span.id = input.name;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $span.textContent = input.title;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $span.classList.add(\"contact-form-error\", \"none\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; input.insertAdjacentElement(\"afterend\", $span);\n&nbsp; &nbsp; &nbsp; &nbsp; });\n\n&nbsp; &nbsp; &nbsp; &nbsp; d.addEventListener(\"keyup\", (e) =&gt; {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (e.target.matches(\".contact-form [required]\")) {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let $input = e.target,\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pattern = $input.pattern || $input.dataset.pattern;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ console.log($input, pattern);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (pattern &amp;&amp; $input.value !== \"\") {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ console.log(\"El input tiene patr\u00f3n\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let regex = new RegExp(pattern);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return !regex.exec($input.value)\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? d.getElementById($input.name).classList.add(\"is-active\")\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : d.getElementById($input.name).classList.remove(\"is-active\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!pattern) {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \/\/ console.log(\"El input NO tiene patr\u00f3n\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return $input.value === \"\"\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? d.getElementById($input.name).classList.add(\"is-active\")\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : d.getElementById($input.name).classList.remove(\"is-active\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; });\n\n&nbsp; &nbsp; &nbsp; &nbsp; d.addEventListener(\"submit\", (e) =&gt; {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.preventDefault();\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const $loader = d.querySelector(\".contact-form-loader\"),\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $response = d.querySelector(\".contact-form-response\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $loader.classList.remove(\"none\");\n  &nbsp; &nbsp; &nbsp; &nbsp; fetch(\"https:\/\/formsubmit.co\/ajax\/youremail@gmail.com\", {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; method: \"POST\",\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body: new FormData(e.target),\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .then((res) =&gt; (res.ok ? res.json() : Promise.reject(res)))\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .then((json) =&gt; {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $loader.classList.add(\"none\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $response.classList.remove(\"none\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $response.innerHTML = `&lt;p&gt;${json.message}&lt;\/p&gt;`;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $form.reset();\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .catch((err) =&gt; {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.log(err);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let message =\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; err.statusText || \"Ocurri\u00f3 un error al enviar el formulario\";\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $response.innerHTML = `&lt;p&gt;Error ${err.status}: ${message}&lt;\/p&gt;`;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .finally(() =&gt; {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setTimeout(() =&gt; {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $response.classList.add(\"none\");\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $response.innerHTML = ``;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, 3000);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });\n&nbsp; &nbsp; &nbsp; &nbsp; });\n&nbsp; &nbsp; &nbsp; }\n\n&nbsp; &nbsp; &nbsp; d.addEventListener(\"DOMContentLoaded\", contactForm());\n&nbsp; &nbsp; &lt;\/script&gt;\n&nbsp; &lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A partir de este ejercicio comenzamos a trabajar con el API de FETCH. Para este ejercicio vamos a crear un archivo llamado&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":1609,"menu_order":3,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_uag_custom_page_level_css":"","footnotes":""},"class_list":["post-1624","page","type-page","status-publish","hentry"],"uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"Sutil Web","author_link":"https:\/\/sutilweb.eu\/index.php\/author\/sutilweb\/"},"uagb_comment_info":0,"uagb_excerpt":"A partir de este ejercicio comenzamos a trabajar con el API de FETCH. Para este ejercicio vamos a crear un archivo llamado...","_links":{"self":[{"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/pages\/1624","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/comments?post=1624"}],"version-history":[{"count":1,"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/pages\/1624\/revisions"}],"predecessor-version":[{"id":1625,"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/pages\/1624\/revisions\/1625"}],"up":[{"embeddable":true,"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/pages\/1609"}],"wp:attachment":[{"href":"https:\/\/sutilweb.eu\/index.php\/wp-json\/wp\/v2\/media?parent=1624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}