En este artículo vamos a explorar los formularios. Los formularios juegan un papel muy importante en el desarrollo de las aplicaciones web, ya que nos permiten proporcionar un mecanismo para que los usuarios puedan realizar tareas de entrada de datos, adjuntar ficheros, etc.

Tipos de formularios: Template-driven forms vs Reative forms

Existen dos tipos de approaches (enfoques) o tipos como prefiráis para poder trabajar con formularios en Angular. Y son:

  • Template-driven Forms: son ideales para trabajar con formularios sencillos.
  • Reactive Forms: son ideales para trabajar con formularios más complejos.

Vamos a hacernos una idea principal de las diferencias entre ambos:


En este artículo nos vamos a basar en explicar el funcionamiento de los formularios basados en Template-Driven Forms:

La comunicación entre los valores de la clase y el formulario de nuestro template HTML se realizará mediante a ngModel.

Como ya hemos visto, están destinados a realizar formularios sencillos.

Creando el proyecto de Angular + bootstrap

Empezamos creando un proyecto con routing:

Una vez creado, vamos a generar nuestro componente que contendrá nuestro formulario:

Y vamos a añadir el selector del componente que acabamos de crear al componente por defecto:

Además añadiremos boostrap a nuestra aplicación. Si no sabes cómo añadirlo te dejo el articulo donde explicamos cómo: Maneras de instalar Bootstrap en Angular (Forma tradicional)

Creando el formulario

Vamos a crear dos clases una que contendrá la persona y otra el país:

Y en este caso en particular, vamos a crear una persona y un array de países sobre la clase my-form.component.ts. Dentro del array de países , definiremos un listado con un id y un nombre por cada uno de los países .

Bien, para poder trabajar con los formularios de tipo template-driven forms, necesitamos añadir FormsModule sobre nuestro módulo:

Para que nuestro formulario se vea centrado en la pantalla, vamos a ir al archivo index.html y vamos a englobar al selector app-root con dos divs de la siguiente manera con el fin de centrar el contenido de nuestro website:

Si ahora escribo el siguiente formulario:

Y creo las clase que recibirá los datos al realizar el envío, en nuestro caso onSubmitForm:

Podemos ver que si abrimos la consola y mostramos los datos, hemos capturado dicha información que hemos escrita en la vista, la hemos traspasado hacía nuestro  typeScript con la función onSubmitForm y hemos mostrado los valores recogidos por consola:

Es muy importante que no nos dejemos ningún atributo en los elementos HTML (a excepción de las clases de Bootstrap) ya que si no no nos funcionará nuestro formulario.

Cuando imprimimos un objeto con los datos del formulario, vemos que se muestran en un diccionario con la estructura:

{

key: value,

key: value,

key: value,

}

El value (valor) es el dato introducido en cada uno de los elementos (input o select en este caso) del formulario y almacenado en el value del objeto. El name de cada input es el encargado de definir el key (el nombre, la clave) de la propiedad.

Otra opción es utilizar el pipe de JSON para mostrar los resultados por pantalla. Vamos a ver un ejemplo:

Si miramos ahora la pantalla conforme escribimos los mensajes nos aparecerán los valores por la pantalla de la siguiente manera:

Si nos fijamos aparecen hasta antes de que los enviemos y así podemos ver lo que enviamos etc antes de enviarlo, esto va muy bien, sobre todo cuando trabajamos con bases de datos, o con verificaciones para ver un resumen de todo lo que se enviará, de esta manera también podemos imprimir estados del formulario, etc.

Si queremos tener otro nombre diferente al name mostrándose, podemos editar el atributo name de la etiqueta:

También podemos mantener el nombre y modificar el key (la clave/nombre) de acceso a cada valor utilizando ngModelGroup:

Si hago otro envío de datos, podemos ver que el nombre cambia:

Validando nuestro formulario template-driven form

Ahora ya tenemos nuestro primer formulario de tipo template-driven form creado. Una vez tenemos operativo nuestro form, vamos a añadirle validaciones:

Para ello, primeramente vamos a hablar sobre los estados de las validaciones. Hasta ahora, le hemos pasado a la función onSubmitForm cuando enviábamos el formulario solamente los datos del formulario, es decir (el value) directamente ya filtrado como parámetro:

Esto limita bastante la respuesta que vamos a poder mostrar en nuestro typeScript. Una alternativa es enviar la respuesta al completo y luego imprimir el value desde el typeScript o lo que queramos sin que nada nos limite.

Si enviábamos datos, podíamos ver solamente los datos del formulario pero realmente un formulario no envía solamente esto sino que nos envía muchas cosas más. Vamos a verlas, para ello, tenemos que modificar el ngSubmit y borrar el parámetro del value. Además, iremos a my-form.component.ts y lo modificaremos para mostrar todo lo que recibimos y también para mostrar solamente los valores de lo que hemos introducido.

Utilizamos el ? para que si no existe esa propiedad no nos salte un error, y por tanto, que solamente se use cuando sea necesario.

Si nos metemos tenemos el siguiente resultado:

Si nos fijamos en nuestro código hemos puesto dos validaciones sobre el input de nombre, que sea requerido y que tenga una longitud mínima de 3 letras para que Ana, Teo, Bob etc. sean válidos. Por lo que para que el campo sea válido, tiene que cumplir ambas condiciones.

Si le doy a enviar puedo comprobar todo lo que envía el formulario cuando realizamos un submit y de donde sale dicha información:

Y dentro de dicho objeto, podemos ver toda la información referente a nuestro formulario. Tanto del formulario en general, como de los campos en particular.

Si por ejemplo, me pongo dentro del input, es decir hago focus (lo selecciono)y salgo:

Estados de un campo:

Pristine (original): significa que no hemos escrito nunca en el campo. Si escribimos sobre dicho campo:

Podemos ver que el campo pasa a dirty (sucio) y ya no volverá nunca más a pristine hasta que no se vuelva a cargar el formulario nuevamente:

Si borramos el valor que hemos escrito:

Como también hemos pedido el focus del input ya hemos hecho click en él y al salir el estado cambia de untouched a touched.

Ahora solamente nos falta que el campo sea válido, para ello, tenemos que escribir algo ya que superar dos validaciones la primera es que es required (requerido) y la segunda que tiene un minlength de 3 (longitud de 3 caracteres mínimo).

Si superamos las dos validaciones, podemos ver que el campo cambia de invalid a valid:

Los estados de un campo, son como una moneda (cara/cruz) o un interuptor (on/off) agrupados en 3 distintos grupos:

  • valid or invalid
  • pristine or dirty
  • touched or untocuhed

Es decir, si no es blanco es negro, si un campo está tocado (touched) ya no puede ser no tocado (untouched) hasta que no volvamos a cargar el formulario. Con el ejemplo que hemos escrito creo que seréis capaces de entenderlo al 100 %.

Validaciones para campos:

Como hemos dicho no tenemos muchas validaciones para este tipo de formularios:

  • minlength(5): controla la longitud mínima de caracteres del campo
  • maxlength(10): controla la longitud máxima de caracteres del campo
  • pattern: nos permite añadir un patrón de Reggex para validar un campo
  • Required: hace que el campo sea requerido. Si no se especifica, solo se deberá de cumplir el resto de las condiciones cuando los campos tengan un valor.

No todas las validaciones pueden ser utilizadas en todos los campos. Por ejemplo en un select utilizaremos required solamente.

Combinando distintos estados de un campo con Validaciones

Hasta ahora, hemos trabajado solamente con individualmente con los estados, pero usualmente se suele trabajar con varios estados a la vez. Por ejemplo con el estado del input touched que nos permitía que cuando escribimos en un input y posteriormente salimos verificamos el resultado. Y combinaremos ese estado con el de manejar el input es válido y si se ha ensuciado.

Además de ello, haremos algo similar con si el input es invalido y si además se ha pulsando el botón de enviar (tipo submit) del formulario.

Para trabajar con la validación de pattern, vamos a añadir un input de email. Lo que quiere decir, que tendremos que ir a la clase persona y añadir un campo de email:

Y ahora vamos a escribir lo siguiente:

Si ahora enviamos el formulario vacío, hasta podemos ver que hemos conseguido mostrar información bastante detallada sobre los errores. Aunque esta información es demasiado técnica para un usuario corriente, nos puede server para ver porque fallan las validaciones o incluso podríamos hasta hacer otros DIVS en el interior de esta y controlar las validaciones mostrando mensajes más descriptivos para nuestros usuarios.

Si nos fijamos, tenemos el problema de que enviamos la información pese a que no está lista hacía el TypeScript. Para que solo se muestre cuando esté lista. Podemos utilizar el status del formulario:

De la siguiente manera:

Si ahora enviamos el formulario estando incorrectamente rellenado, vemos que no se muestra la información por consola:

Si lo rellenamos correctamente:

Podemos eliminar/comentar el mensaje de valid del formulario, ya que solo mostraremos advertencias cuando el formulario este incorrecto.

También podemos observar que tenemos muchos errores distintos:

Trabajando con los estados de Angular

Hasta ahora hemos visto la forma de mostrar advertencias/alertas sobre los inputs de nuestros formularios.

Pero cuando trabajamos con los formularios de Angular, el propio Angular para realizar las comprobaciones sobre los estados de los campos de nuestros formularios, nos agregar sobre dichos campos  una serie de clases  de forma automática.

Dichas clases no son nada más y nada menos que los estados que acabábamos de ver anteriormente con la única diferente que tienen un ng- delante de cada uno de los estados:

De hecho si vamos al inspector del navegador sobre nuestro formulario podemos ver que si aún no hemos tocado el formulario nos aparece de la siguiente manera:

Si nos ponemos encima del input y salimos podemos ver que el estado de ng-untouched cambiará a ng-touched:

Y podemos hacer lo mismo con el resto de estados sin problema.

Si queremos añadir estilos a los inputs que nos indiquen si los inputs son correctos o incorrectos, a parte de las advertencias que ya mostramos actualmente,  lo primero que se nos pasa por la cabeza es aplicar los estilos manualmente. Trabajando con los estados que ya conocíamos y sin usar/apoyarnos en estás clases que automáticamente Angular aplica sobre nuestros inputs.

Y es totalmente válido, y una opción respetable aunque sea el camino más largo y engorroso. Vamos a ver un ejemplo:

  • Con BootStrap y los estados manuales podríamos hacer lo siguiente:

Añadimos la clase was-validated sobre el formulario y escribimos los estados tal cual los tenemos en el ngIf sobre la propiedad [ngClass] y si devuelve true aplicará la clase is-invalid de Bootstrap y si devuelve false aplicará la clase is-valid de Bootstrap.

Os adjunto el código al completo también:

Si ahora vamos al formulario, podemos ver que nos muestra de forma más visual si los inputs son correctos o incorrectos:

  • Con los estados de angular (ng-valid, ng-invalid, etc,) y los estados automáticos podríamos hacer lo siguiente:

Existe una forma más sencilla de realizar esto con Angular desde CSS a través de las clases ng-valid, ng-invalid, etc.

Vamos a ver un ejemplo:

Si añadimos las siguientes clases a nuestro CSS del componente:

Y eliminamos lo añadido anteriormente para el ejemplo de bootstrap dejando el template de la siguiente manera:

Vamos a quitarle le required al primer campo (el campo del name). Y si ahora ejecutamos el formulario, podemos observar que cuando el formulario se muestra de la siguiente manera:

Al no ser un campo requerido, no sería necesario validarlo a excepción de que si que tenga contenido

Si lo cambiamos por el contenido correcto, a deferencia de los campos required, podemos observar que este no muestra una validación en verde.

Os dejo una imagen que lo explica a las mil maravillas:

Deshabilitar botón si el formulario no es válido o un input no es válido

También podemos deshabilitar un botón o un campo en función de si el formulario u otro campo son válidos.

Vamos a ver un ejemplo:

Si invalidamos el botón de enviar, deshabilitandolo a través del atributo disabled, podemos ver que si el formulario no es válido no se activará y, por tanto, no lo podremos pulsar:

Si rellenamos el formulario podemos ver que ahora si que nos funciona:

Otra opción sería deshabilitar un campo si el input del correo no es válido. Para ello, vamos a volver a trabajar con el botón de enviar y realizaremos lo siguiente:

Vemos que el botón de enviar está deshabilitado y solamente se habilita cuando el formulario es válido.

Lo podríamos aplicar sobre cualquier campo del formulario, eso sí, siempre fijandonos de esconder también la validación.

Link a repositorio de GitHub del ejemplo

Esto es todo por hoy, espero que os haya gustado y os haya servido para entender mejor cómo funcionan los Formularios en Angular. Un saludo y hasta la próxima 🙂