Creación y validación de formularios con el módulo ReactiveFormsModule

Formularios y Validación en Angular (II)

Rodrigo Bosarreyes
4 min readSep 29, 2023
Photo by Florian Olivo on Unsplash

Como vimos en la clase anterior, Angular nos ofrece el módulo ReactiveForms, el cual nos provee de una serie de clases que nos facilita trabajar con este tipo de formularios, en esta clase vamos a ver cómo se codifica.

Lo primero que debemos hacer es importar el módulo ReactiveFormsModule en nuestra aplicación. Para hacerlo, abre el archivo de módulo donde quieres implementarlo (por defecto src/app/app.module.ts) y agrega la importación de ReactiveFormsModule de la siguiente manera:

app.module.ts

Ahora que hemos importado ReactiveFormsModule, podemos comenzar a crear nuestro formulario reactivo. En este ejemplo, crearemos un formulario de inicio de sesión con campos para correo electrónico y contraseña.

Abre el archivo src/app/app.component.ts (en mi caso he creado un LoginComponent, pero puedes hacerlo en el AppComponent sin problema) y agrega el siguiente código:

login.component.ts

Presta especial atención en la línea 4 donde se define el tipo del formulario, aquí se definen qué campos tendrá y de qué tipo serán, en este caso, se trata de email y password ambos de tipo string (no pueden ser null).
Inyectamos FormBuilder, en este caso como los campos no pueden ser null utilizamos su variante NonNullableFormBuilder.
En la línea 21 creamos el formulario SIN utilizar FormBuilder, este código es meramente ejemplificativo para que puedas ver la diferencia entre una manera u otra.
En la línea 26 se crea el formulario ayudándonos del FormBuilder.
Por último, en la línea 32, creamos el método que se invocará al enviar el formulario, en este caso solo nos interesa comprobar que el formulario sea válido y en caso de serlo se mostrará un contenido del mismo por consola.

Ahora que tenemos el formulario reactivo, necesitamos crear la plantilla HTML correspondiente. Abre el archivo src/app/app.component.html y agrega el siguiente código:

<div class="container">
<h2>Iniciar Sesión</h2>
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="email">Correo Electrónico:</label>
<input
type="email"
class="form-control"
id="email"
formControlName="email"
/>
<div
*ngIf="loginForm.get('email')?.hasError('required') && loginForm.get('email')?.touched"
class="alert alert-danger"
>
El correo electrónico es obligatorio.
</div>
<div
*ngIf="loginForm.get('email')?.hasError('email') && loginForm.get('email')?.touched"
class="alert alert-danger"
>
Ingresa un correo electrónico válido.
</div>
</div>
<div class="form-group">
<label for="password">Contraseña:</label>
<input
type="password"
class="form-control"
id="password"
formControlName="password"
/>
<div
*ngIf="loginForm.get('password')?.hasError('required') && loginForm.get('password')?.touched"
class="alert alert-danger"
>
La contraseña es obligatoria.
</div>
<div
*ngIf="loginForm.get('password')?.hasError('minlength') && loginForm.get('password')?.touched"
class="alert alert-danger"
>
La contraseña debe tener al menos 6 caracteres.
</div>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!loginForm.valid">
Iniciar Sesión
</button>
</form>
</div>

En la plantilla HTML, puedes usar la directiva formGroup para especificar que el formulario está asociado al FormGroup definido en el componente. Esto se hace en el elemento <form>. Además, usa la directiva formControlName en los elementos de entrada (<input>) para conectar cada campo del formulario con su respectivo FormControl.

En otras palabras, en la plantilla HTML necesitas enlazar cada elemento a un FormControl mediante la directiva formControlName, además, estos elementos deben estar encapsulados en algún elemento padre enlazado con el FormGroup al que pertenecen los FormControl, para ello utiliza la directiva formGroup.

También te dejo su SCSS:

.container {
max-width: 400px;
margin: 0 auto;
padding: 20px;
text-align: center;

h2 {
margin-bottom: 20px;
}

form {
.form-group {
text-align: left;
margin-bottom: 20px;

label {
display: block;
font-weight: bold;
}

input {
width: 100%;
padding: 10px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 4px;

&:focus {
outline: none;
border-color: #007bff;
}
}

.alert {
color: #721c24;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 4px;
padding: 5px 10px;
margin-top: 5px;
font-size: 14px;
}
}

button {
width: 100%;
padding: 10px;
font-size: 18px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;

&:disabled {
background-color: #ccc;
cursor: not-allowed;
}
}
}
}

Si lanzamos nuestra aplicación con ng serve tendremos el siguiente resultado:

Como puedes ver, aparentemente funciona, pero no hemos añadido ninguna validación, tendríamos que validar que el email tenga el formato adecuado y que tanto el email como la contraseña sean campos obligatorios.

Afortunadamente, Angular nos ofrece una serie de validadores predefinidos como pueden ser valor mínimo/máximo (en caso de números), longitud mínima/máxima (en caso de texto), obligatorio y uno especial para validar el formato del email.

login.component.ts

Importante: presta mucha atención que los validadores están encapsulados en un array, esto es importante que sea así porque al crear un control recibe como primer parámetro el valor del control, como segundo un listado de validadores síncronos y como tercer parámetro un listado de validadores asíncronos.

Si ahora intentamos añadir un carácter inválido o lo dejamos vacío:

Seguramente después de esta clase te han surgido más dudas, como por ejemplo ¿qué es eso de touched en el HTML? ¿Cómo modificar un FormControl desde código? ¡Todo esto lo veremos en la siguiente clase!

--

--