Ir al contenido
wannacode

Formularios

En resumen: Un formulario envía solo los campos que tienen name, la etiqueta <label> une el texto con el campo, y los atributos required, type, min, max y pattern hacen que el navegador compruebe lo escrito antes de enviarlo.

Problema

Un pedido sin datos

La tienda recibe pedidos sin nombre y sin teléfono. Los compradores juran que rellenaron todo. Aquí está el formulario de compra. Rellénalo y pulsa «Hacer el pedido».

HTML, CSS, JS
index.html

El sandbox no envía nada por la red. En su lugar, la consola dice lo que se habría enviado: «El formulario se envió: (sin campos)». Todo lo que escribiste se quedó en la página. Hay también una segunda señal: un clic en la palabra «Nombre» no pone el cursor en el campo. En pantalla el texto y el campo están uno al lado del otro, pero nada en el árbol los une.

La idea

El formulario, el name y la etiqueta

Un formulario (<form>) reúne campos y los envía juntos. action dice adónde (/order), y method dice cómo (post).

<form action="/order" method="post">
<label for="phone">Teléfono</label>
<input id="phone" name="phone" type="tel">
<button type="submit">Hacer el pedido</button>
</form>
  • name es lo que se envía. Al enviar, el navegador hace un par name=value por cada campo que tiene nombre: phone=0888123456. Un campo sin name no se envía, por lleno que esté. Por eso el pedido iba vacío.
  • <label> es la etiqueta del campo. Se une con for, que apunta al id del campo. El campo también puede ir dentro de la etiqueta: <label>Teléfono <input name="phone"></label>. Entonces no hace falta for.

La etiqueta le da al campo un nombre en el árbol de accesibilidad. Un lector de pantalla dice «Teléfono, cuadro de texto», no solo «cuadro de texto». Un clic en la etiqueta pone el foco en el campo, y una casilla con etiqueta se puede marcar con su texto. Las comprobaciones de las tareas encuentran el campo por su etiqueta, como lo hace una persona.

id y name suelen ser iguales, pero hacen trabajos distintos. El id es para la etiqueta y para CSS, y el name es la clave en la petición.

La idea

Los tipos de campos

<input> es un campo, y type dice qué es:

  • text (el predeterminado), email, tel: texto. En el móvil email y tel abren un teclado con @ o con dígitos.
  • number: un número, con flechas. min="1", max="10" y step="1" dan los límites y el paso.
  • checkbox: una marca de sí o no. Se envía solo cuando está marcada: gift=yes por value="yes". Sin value envía gift=on.
  • radio: una opción entre varias. Los botones de opción forman un grupo por un name compartido: name="delivery" en los dos, y value dice cuál está elegido. Solo se envía el elegido.

Otros campos:

  • <select> con <option>: un menú desplegable. Envía el value de la opción elegida, o su texto cuando no hay value.
  • <textarea>: texto en varias líneas, como una nota para el repartidor.
  • <fieldset> con <legend>: un grupo de campos con un título. Los botones de opción de la entrega están en un fieldset, y la legend «Entrega» es el nombre del grupo. Sin ella un lector de pantalla dice «A una sucursal», pero no para qué es la sucursal.

El botón. <button type="submit"> envía el formulario. <button type="button"> no hace nada por sí solo, y su acción está en JavaScript. Dentro de un formulario un <button> sin type es submit. Así que escribe siempre el type.

Míralo

La compra completa

El formulario de compra con todos los tipos de campos. Rellénalo, cambia la ciudad y la entrega y pulsa «Hacer el pedido». Marca «Envolver para regalo» y pulsa otra vez.

HTML, CSS, JS
index.html

Mira la línea de la consola. Los pares están en el orden de los campos del código. La ciudad es plovdiv: se envía el value, no el texto «Plovdiv». De la entrega solo está el botón elegido. La casilla falta mientras no se marca. La nota vacía se envía como note=: un campo vacío con nombre sigue siendo un campo.

Pruébalo

Arregla la compra

Arregla el formulario del principio para que el pedido llegue completo. Los textos «Nombre», «Teléfono» y «Dirección» pasan a ser las etiquetas de sus campos, y los campos reciben los nombres name, phone y address.

HTML, CSS, JS
index.html

Pruébalo

Encuentra el error

La compradora escribe un código de descuento y pulsa «Aplicar el código». El pedido se envía antes de que haya escrito su correo electrónico. ¿Qué línea tiene la culpa?

Elige la línea con el error.

Pruébalo

Completa

¿Qué atributo de la etiqueta apunta al id del campo?

<label ="email">Correo electrónico</label>
<input id="email" name="email" type="email">

La idea

Las comprobaciones del navegador

Un pedido con el correo ana o con una cantidad de 0 no debería enviarse. El navegador puede comprobar mucho por sí solo, sin una línea de JavaScript. Las reglas son atributos del campo:

  • required: el campo no puede estar vacío. En una casilla: debe estar marcada. En un grupo de botones de opción: algo debe estar elegido.
  • type="email": el texto debe parecer un correo electrónico (nombre@dominio). Un campo vacío pasa si no hay required.
  • min y max: los límites de un número. step es el paso: con step="1", 2,5 no pasa.
  • minlength y maxlength: cuántos caracteres como mínimo y como máximo.
  • pattern: un patrón para todo el texto, como una expresión regular. pattern="0[0-9]{9}" es un 0 y nueve dígitos más.

Cuando se pulsa «Hacer el pedido», el navegador comprueba cada campo. Si uno no pasa, el formulario no se envía y el evento submit no llega a ocurrir. El navegador pone el foco en el primer campo no válido y muestra al lado un mensaje en el idioma del navegador. La compradora lo corrige, pulsa otra vez, y el navegador comprueba desde el principio.

novalidate en el <form> desactiva estas comprobaciones. Se usa cuando la página comprueba y muestra los errores con su propio código. De eso trata la lección sobre formularios en componentes.

Míralo

Mira qué pasa con «Hacer el pedido»

El código es un formulario de compra corto. Fíjate en el orden: primero la comprobación, luego el evento, luego la recogida.

<form action="/order" method="post">
<label>Nombre <input name="name" required></label>
<label>Correo <input name="email" type="email" required></label>
<label>Teléfono <input name="phone" pattern="0[0-9]{9}"></label>
<label>Cantidad <input name="qty" type="number" min="1" max="10"></label>
<label><input name="gift" type="checkbox"> Regalo</label>
<button>Hacer el pedido</button>
</form>
Paso a paso, en palabras
  1. El comprador pulsa «Hacer el pedido». El <button> no tiene type, así que dentro de un formulario es un botón de envío. El navegador todavía no envía nada.
  2. Primero comprueba cada campo, en el orden del código, contra sus reglas. «iva» no es un correo electrónico, y «12345» no cumple el patrón.
  3. Hay campos no válidos, así que el evento submit no ocurre. El navegador pone el foco en el primer campo no válido y muestra un mensaje solo para él.
  4. El comprador corrige el correo y el teléfono y pulsa otra vez.
  5. La misma comprobación desde arriba. Esta vez todos los campos pasan.
  6. Solo ahora ocurre el evento submit. Si el código no lo detiene, el navegador envía el formulario a la dirección de action con el método de method.
  7. Recoge un par name=value de cada campo con nombre. La casilla sin marcar no se envía en absoluto.
  8. Con method="post" los pares van en el cuerpo de la petición, unidos con &. La clave es el atributo name, no el texto de la etiqueta.

El navegador comprueba todos los campos, pero muestra un mensaje solo para el primero no válido. Por eso una compradora a veces corrige un campo y enseguida ve un mensaje para el siguiente. Y gift no se envía en absoluto: para el servidor una casilla sin marcar y un campo que falta son lo mismo.

Pruébalo

Añade las comprobaciones

El pedido rápido del pan deja pasar todo. Añade comprobaciones: la cantidad va de 1 a 10, el correo electrónico es obligatorio y debe ser un correo, el teléfono es obligatorio y es un 0 y nueve dígitos más. La comprobación escribe 12, un correo vacío, «iva», un teléfono vacío y uno incorrecto, y espera que el navegador se detenga en el campo correcto.

HTML, CSS, JS
index.html
Más precisamente, para curiosos

El servidor comprueba otra vez. La comprobación del navegador es una comodidad para la compradora: ve el error enseguida. No protege la tienda. novalidate, el panel Elements o una petición enviada sin navegador la saltan, así que el servidor comprueba cada campo otra vez. Por qué es así se explica en la lección «Entrada no confiable».

Qué no se envía. Un campo sin name, una casilla sin marcar, un botón de opción no elegido y un campo con disabled. Un campo con readonly sí se envía: solo que no se puede cambiar. Los archivos (type="file") necesitan method="post" y enctype="multipart/form-data".

Cómo se envía. Con method="get" (el predeterminado) los pares van en la dirección: /order?name=…&phone=…. Con method="post" van en el cuerpo de la petición. En ambos casos se codifican: @ pasa a ser %40, y un espacio pasa a ser +.

Enter. Enter en un campo de texto envía el formulario como un clic en el botón de envío, con las mismas comprobaciones.

minlength y un valor desde código. minlength comprueba solo el texto que escribió una persona. Un valor del atributo value o de JavaScript pasa, aunque sea corto.

Sin comprobaciones. formnovalidate en un botón envía sin comprobar (por ejemplo, «Guardar borrador»). form.submit() desde JavaScript tampoco comprueba y no dispara el evento submit, mientras que form.requestSubmit() hace todo lo que hace un clic.

Dar estilo a los errores. CSS ve los campos no válidos con :invalid, y :user-invalid los detecta solo después de que una persona los ha tocado. Así un campo no está en rojo antes de que la compradora haya escrito nada. El módulo siguiente trata de CSS.

autocomplete. autocomplete="email", "tel", "name", "street-address" le dicen al navegador qué ofrecer de lo que recuerda. La compradora rellena la compra con dos clics.

Ejercicio

El formulario de compra

Haz desde cero el formulario de compra, con los campos en este orden. «Nombre» (name), obligatorio. «Correo electrónico» (email), un correo obligatorio. «Teléfono» (phone), obligatorio, un 0 y nueve dígitos más. «Ciudad» (city): un menú desplegable Sofía, Plovdiv, Varna con los valores sofia, plovdiv, varna. Un grupo «Entrega» con dos botones de opción (delivery): «A la dirección» (address), elegido al principio, y «A una sucursal» (office). «Nota para el repartidor» (note), en varias líneas. Una casilla «Envolver para regalo» (gift) con el valor yes. Un botón «Hacer el pedido».

HTML, CSS, JS
index.html

Test

Ponte a prueba

1. La compradora escribió «Ana» en un campo <input id="name"> sin name. ¿Qué envía el formulario?
2. Dos botones de opción de la entrega tienen name="courier" y name="office". ¿Qué pasa?
3. El campo es <input name="email" type="email" required>, y la compradora escribió ana. ¿Qué hace el navegador con «Hacer el pedido»?
4. ¿Por qué comprueba el servidor el pedido si el navegador ya lo comprobó?
5. Un formulario tiene <button>Aplicar el código</button> sin type. ¿Qué hace un clic en él?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·