¿Cómo aplicar validación a formularios reactivos en Angular?

Es posible que ya hayas completado un formulario que no indicaba claramente por qué un campo no era válido y tenías que adivinar cuántos caracteres debía tener tu contraseña o qué tipo de caracteres debía tener. O, en un formulario largo, ¿alguna vez completó solo los campos que creía que eran obligatorios y solo al final, al intentar enviar los datos, se encontró con numerosos mensajes de error que mostraban que varios otros campos eran obligatorios? Aburrido, ¿verdad? ¡Ven a aprender cómo mejorar esta experiencia utilizando las validaciones personalizadas de Angular!
En este artículo, aprenderás cómo:
- Crear un formulario reactivo;
- Aplicar validaciones estándar y crear validaciones personalizadas;
- Mostrar errores de validación solo cuando se accede al campo;
- Habilitar el botón para enviar datos solo cuando el formulario sea válido.
¿Vamos?
Crear formularios es algo muy común en la rutina de los desarrolladores front-end. Tanto en formularios más simples como, sobre todo a medida que crece el número de campos del formulario, es necesario implementar validaciones.
Las validaciones son importantes para evitar errores de registro y garantizar que la información completada tenga el formato esperado, pero es necesario dejar claras todas las particularidades de los campos a completar, para promover una interacción más dinámica y amigable entre las personas. y nuestra aplicación.
¿Qué son formularios reactivos?
En Angular, hay dos tipos diferentes de formularios: basados en plantillas y basados en datos . Los basados en plantillas se crean y configuran en component.html
; Las validaciones también se incluyen en la plantilla y los valores del formulario se envían a través de la directiva ngSubmit .
Los formularios basados en datos se crean y configuran en el component.ts
y la mayor parte del código está en este archivo y no en el HTML. De esta manera, tenemos una plantilla más limpia, con sólo la estructura básica del formulario, ya que todas las validaciones se realizan en el componente. En el html, la plantilla está asociada con el componente y no necesariamente necesitamos ngSubmit .
Fáciles de crear y mantener, los formularios reactivos, como también se les conoce, son ampliamente utilizadas debido a su poder y capacidad de reaccionar ante los cambios que ocurren en el formulario, utilizando observables.
Ahora entenderemos cómo podemos crear un formulario reactivo y aplicarle validaciones.
¿Qué necesitamos configurar?
Con la aplicación creada, necesitamos importar el ReactiveFormsModule en los imports del componente, así :
import { ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-formulario',
imports: [ContainerComponent,
SeparadorComponent,
ReactiveFormsModule,
CommonModule,
RouterLink],
templateUrl: './formulario.component.html',
styleUrl: './formulario.component.css'
})
export class MiComponente { }
Si tienes dudas sobre este paso, mira aquí cómo empezar con Angular .
Ahora vamos a crear en app.component.ts
una variable llamada formulario de tipo FormGroup (también debe importarse), que es una clase de Angular que nos ayudará en la implementación y validación de formularios. Otra clase importante que veremos más adelante es FormControl .
import { FormGroup } from '@angular/forms';
formulario: FormGroup;
El enfoque que utilizaremos para crear nuestro formulario es mediante inyección de dependencia del servicio FormBuilder . Este servicio proporciona métodos para generar controles de formulario y evita la creación manual de instancias de control. Para ello tendremos que:
- Importar la clase FormBuilder;
- Inyectar el servicio FormBuilder;
- Generar el contenido del formulario.
Creemos un formulario con 4 campos:
- nombre
- nombre de usuario
- correo electrónico
- contraseña
Nuestro app.component.ts
se verá así:
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
formulario: FormGroup;
constructor(private formBuilder: FormBuilder) { }
ngOnInit(): void {
this.formulario = this.formBuilder.group({
nombre: [''],
username: [''],
email: [''],
contraseña: ['']
});
}
}
También necesitamos crear la estructura del formulario en la plantilla con los cuatro campos. Ahora, antes de implementar las validaciones, sincronicemos el formulario creado en el componente con la plantilla para ver si todo está bien.
Para hacer esto podemos usar una directiva ReactiveFormsModule
llamada formGroup . Y en la tag form de HTML , asignaremos la directiva a nuestra variable formulario y haremos un property binding , porque cada vez que se modifica el campo, queremos actualizar y asignar el valor al formulario.
<form [formGroup]="formulario"></form>
Para asociar cada entrada usamos otra directiva llamada formControlName , haciendo un enlace entre el campo en el html y el componente y pasando exactamente el nombre de las variables que creamos a través de FormBuilder.
<input id="nombre" type="text" formControlName="nombre" >
<input id="username" type="text" formControlName="username" >
<input id="email" type="email" formControlName="email" >
<input id="contraseña" type="password" formControlName="contraseña" >
Nuestro formulario se ve así (estilizado con Angular Material ).
Aplicando validaciones
Ahora, incluyamos las siguientes validaciones en la aplicación:
- Todos los campos serán obligatorios;
- El campo de username sólo aceptará letras minúsculas;
- Verificación del formato correcto del correo electrónico;
- El número mínimo de caracteres para la contraseña será 6.
Para comenzar, importemos la clase Validators :
import { Validators } from '@angular/forms';
Esta clase ya cuenta con varios métodos de validación listos y fáciles de usar, como por ejemplo:
- required() - campo obligatorio;
- maxLength() - número máximo de caracteres permitidos;
- minLength() - número mínimo de caracteres permitidos;
- email() - valida el formato del correo electrónico;
Vea la lista completa de métodos de la clase Validators aquí .
Ahora implementemos las validaciones en el formulario, pasando los métodos de validación como segundo parámetro del array creado en el component.ts
.
ngOnInit(): void {
this.formulario = this.formBuilder.group({
nombre: ['', [Validators.required]],
username: ['', [Validators.required]],
email: ['', [Validators.required, Validators.email]],
contraseña: ['', [Validators.required, Validators.minLength(6)]]
});
}
Mostrando mensajes de error
Para mostrar mensajes relacionados con validaciones incluiremos en el html, debajo del input, un div usando @if
, pasando el formulario y tomando errores del campo pasado como parámetro, e incluyendo el mensaje que queremos presentar:
<div @if (formulario.get('nombre')?.invalid && formulario.get('nombre')?.dirty) { } >
Nombre es obligatorio
</div>
Tradicionalmente, se ha utilizado
*ngIf
para mostrar mensajes de error condicionalmente. Sin embargo, a partir de Angular 17, se introdujo una nueva sintaxis de control de flujo basada en bloques con@
que ofrece una forma más limpia y legible de manejar estas situaciones.
Repitamos esto en cada campo y veamos el resultado:
Ok, ahora van apareciendo los mensajes, pero ya cuando la aplicación se carga inicialmente. ¿Existe una forma más amigable de presentarlos? ¿Solo cuando se accede al campo? ¡¡Sí!! Podemos hacer esto a través de una propiedad FormControl llamada touch . Su valor inicial es false y siempre que la entrada desencadena el evento onBlur , es decir, cuando se accede al campo y pierde el foco, la propiedad recibe el valor true .
En el ejemplo del campo de nombre se verá así:
<div @if (formulario.get('nombre')?.invalid && (formulario.get('nombre')?.dirty || formulario.get('nombre')?.touched)) { } >
Nombre es obligatorio
</div>
Al replicarse en los demás campos, los mensajes de error ahora solo aparecen cuando es necesario.
Creando validaciones personalizadas
La validación que queremos incluir para que el campo de nombre de usuario solo reciba letras minúsculas no está presente en la clase Validators
. Pero está bien, ya que puedes crear innumerables validaciones personalizadas que satisfagan tus necesidades. En nuestro ejemplo, creamos un archivo llamado minusculoValidator.ts
, importamos la clase Control abstracto y creamos la lógica de validación.
minusculoValidator.ts
:
import { AbstractControl } from "@angular/forms";
export function minusculoValidator(control: AbstractControl) {
const username = control.value as string;
if(username !== username?.toLowerCase()) {
return { minusculo: true };
} else
return null;
}
Después de eso, importamos la validación al componente y la incluimos en la matriz junto con las otras validaciones.
app.component.ts
:
username: ['', [Validators.required, minusculoValidator]],
app.component.html
:
<div @if (formulario.get('username')?.errors?.['minusculo'] && formulario.get('username')?.touched) { } >
Este campo solo acepta letras minúsculas
</div>
Así, a través de la propiedad errors , podremos crear mensajes personalizados en función del error que se desencadene.
Deshabilitar/Habilitar el botón
Otro punto importante es que el botón para enviar datos está habilitado desde el principio, incluso si los campos no han sido completados. ¿Resolvemos esto?
El formulario tiene la propiedad valid y podemos hacer un enlace de propiedad asignándolo a la propiedad deshabilitada del botón y así crear lógica para que el botón solo esté habilitado cuando el formulario sea válido, es decir, cuando todos los campos estén llenos correctamente.
app.component.html
:
<button [disabled]="!formulario.valid">
Crear cuenta
</button>
Aquí tenemos el resultado final:
Conclusión
En este artículo, aprendimos cómo crear un formulario reactivo usando el servicio FormBuilder, cómo aplicar validaciones a través de la clase Validators y crear validaciones personalizadas. Además, vimos cómo mostrar mensajes de error personalizados y habilitar/deshabilitar el botón de envío de datos según el estado del formulario.
¿Quieres aprender más sobre Angular? Ve a nuestra capacitación y aplica todo lo que se aprendió sobre la validación de formularios reactivos.
Artículo adaptado y traducido por Daysibel Cotiz.
Nayanne Batista
Nayanne (Nay) es oriunda de Paraíba y realizó una transición profesional a TI luego de realizar un doctorado en el área de la salud y ser profesora en educación superior. Licenciada en Análisis y Desarrollo de Sistemas, ha trabajado como Dev Frontend en proyectos y ahora es Instructora en Alura. Cree plenamente en el poder transformador de la educación y la tecnología en la vida de las personas. ¡Le encantan los libros y el café!