Introducción
Los formularios reactivos en Angular proporcionan una forma más robusta y escalable de manejar formularios en comparación con los formularios basados en plantillas. Utilizan una aproximación programática para crear y gestionar formularios, lo que permite un mayor control sobre la validación y el estado del formulario.
Conceptos Clave
- FormGroup: Representa un grupo de controles de formulario.
- FormControl: Representa un control individual de formulario.
- FormArray: Representa una matriz de controles de formulario.
- Validators: Funciones que se utilizan para validar los controles de formulario.
Configuración Inicial
Para empezar a trabajar con formularios reactivos, primero debemos asegurarnos de que el módulo ReactiveFormsModule
esté importado en nuestro módulo principal o en el módulo donde se utilizarán los formularios.
import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ // otros módulos ReactiveFormsModule ], // otros metadatos }) export class AppModule { }
Creación de un Formulario Reactivo
Paso 1: Definir el Formulario en el Componente
Primero, importamos las clases necesarias desde @angular/forms
y definimos nuestro formulario en el componente.
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; @Component({ selector: 'app-reactive-form', templateUrl: './reactive-form.component.html', styleUrls: ['./reactive-form.component.css'] }) export class ReactiveFormComponent implements OnInit { myForm: FormGroup; ngOnInit() { this.myForm = new FormGroup({ 'name': new FormControl(null, [Validators.required, Validators.minLength(3)]), 'email': new FormControl(null, [Validators.required, Validators.email]), 'age': new FormControl(null, [Validators.required, Validators.min(18)]) }); } onSubmit() { console.log(this.myForm.value); } }
Paso 2: Vincular el Formulario en la Plantilla
En el archivo de plantilla HTML, utilizamos las directivas formGroup
y formControlName
para vincular nuestro formulario reactivo.
<form [formGroup]="myForm" (ngSubmit)="onSubmit()"> <div> <label for="name">Name</label> <input id="name" formControlName="name"> <div *ngIf="myForm.get('name').invalid && myForm.get('name').touched"> <small *ngIf="myForm.get('name').errors.required">Name is required.</small> <small *ngIf="myForm.get('name').errors.minlength">Name must be at least 3 characters long.</small> </div> </div> <div> <label for="email">Email</label> <input id="email" formControlName="email"> <div *ngIf="myForm.get('email').invalid && myForm.get('email').touched"> <small *ngIf="myForm.get('email').errors.required">Email is required.</small> <small *ngIf="myForm.get('email').errors.email">Invalid email format.</small> </div> </div> <div> <label for="age">Age</label> <input id="age" formControlName="age" type="number"> <div *ngIf="myForm.get('age').invalid && myForm.get('age').touched"> <small *ngIf="myForm.get('age').errors.required">Age is required.</small> <small *ngIf="myForm.get('age').errors.min">You must be at least 18 years old.</small> </div> </div> <button type="submit" [disabled]="myForm.invalid">Submit</button> </form>
Validación de Formularios
Validadores Incorporados
Angular proporciona varios validadores incorporados que se pueden utilizar para validar los controles de formulario. Algunos de los más comunes son:
Validators.required
: El control es obligatorio.Validators.minLength(length: number)
: El control debe tener al menos una longitud mínima.Validators.maxLength(length: number)
: El control debe tener una longitud máxima.Validators.email
: El control debe ser un correo electrónico válido.Validators.min(min: number)
: El control debe tener un valor mínimo.Validators.max(max: number)
: El control debe tener un valor máximo.
Validadores Personalizados
También podemos crear validadores personalizados para necesidades específicas.
import { AbstractControl, ValidationErrors } from '@angular/forms'; export function forbiddenNameValidator(control: AbstractControl): ValidationErrors | null { const forbidden = /admin/.test(control.value); return forbidden ? { 'forbiddenName': { value: control.value } } : null; }
Luego, aplicamos el validador personalizado a un control de formulario.
this.myForm = new FormGroup({ 'name': new FormControl(null, [Validators.required, Validators.minLength(3), forbiddenNameValidator]), 'email': new FormControl(null, [Validators.required, Validators.email]), 'age': new FormControl(null, [Validators.required, Validators.min(18)]) });
Ejercicio Práctico
Ejercicio
Crea un formulario reactivo con los siguientes campos:
- Username: Obligatorio, mínimo 5 caracteres.
- Password: Obligatorio, mínimo 8 caracteres.
- Confirm Password: Obligatorio, debe coincidir con el campo Password.
- Email: Obligatorio, debe ser un correo electrónico válido.
Solución
Componente TypeScript
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, Validators } from '@angular/forms'; @Component({ selector: 'app-signup-form', templateUrl: './signup-form.component.html', styleUrls: ['./signup-form.component.css'] }) export class SignupFormComponent implements OnInit { signupForm: FormGroup; ngOnInit() { this.signupForm = new FormGroup({ 'username': new FormControl(null, [Validators.required, Validators.minLength(5)]), 'password': new FormControl(null, [Validators.required, Validators.minLength(8)]), 'confirmPassword': new FormControl(null, [Validators.required]), 'email': new FormControl(null, [Validators.required, Validators.email]) }, { validators: this.passwordMatchValidator }); } passwordMatchValidator(form: FormGroup) { return form.get('password').value === form.get('confirmPassword').value ? null : { 'mismatch': true }; } onSubmit() { console.log(this.signupForm.value); } }
Plantilla HTML
<form [formGroup]="signupForm" (ngSubmit)="onSubmit()"> <div> <label for="username">Username</label> <input id="username" formControlName="username"> <div *ngIf="signupForm.get('username').invalid && signupForm.get('username').touched"> <small *ngIf="signupForm.get('username').errors.required">Username is required.</small> <small *ngIf="signupForm.get('username').errors.minlength">Username must be at least 5 characters long.</small> </div> </div> <div> <label for="password">Password</label> <input id="password" formControlName="password" type="password"> <div *ngIf="signupForm.get('password').invalid && signupForm.get('password').touched"> <small *ngIf="signupForm.get('password').errors.required">Password is required.</small> <small *ngIf="signupForm.get('password').errors.minlength">Password must be at least 8 characters long.</small> </div> </div> <div> <label for="confirmPassword">Confirm Password</label> <input id="confirmPassword" formControlName="confirmPassword" type="password"> <div *ngIf="signupForm.errors?.mismatch && signupForm.get('confirmPassword').touched"> <small>Passwords do not match.</small> </div> </div> <div> <label for="email">Email</label> <input id="email" formControlName="email"> <div *ngIf="signupForm.get('email').invalid && signupForm.get('email').touched"> <small *ngIf="signupForm.get('email').errors.required">Email is required.</small> <small *ngIf="signupForm.get('email').errors.email">Invalid email format.</small> </div> </div> <button type="submit" [disabled]="signupForm.invalid">Submit</button> </form>
Conclusión
Los formularios reactivos en Angular proporcionan una forma poderosa y flexible de manejar formularios complejos. Al utilizar FormGroup
, FormControl
y validadores, podemos crear formularios robustos y escalables con validación personalizada. En el siguiente módulo, exploraremos cómo validar y manejar formularios dinámicos en Angular.
Curso de Angular
Módulo 1: Introducción a Angular
- ¿Qué es Angular?
- Configuración del Entorno de Desarrollo
- Arquitectura de Angular
- Primera Aplicación Angular
Módulo 2: Componentes de Angular
- Entendiendo los Componentes
- Creación de Componentes
- Plantillas de Componentes
- Estilos de Componentes
- Interacción entre Componentes
Módulo 3: Enlace de Datos y Directivas
- Interpolación y Enlace de Propiedades
- Enlace de Eventos
- Enlace de Datos Bidireccional
- Directivas Incorporadas
- Directivas Personalizadas
Módulo 4: Servicios e Inyección de Dependencias
- Introducción a los Servicios
- Creación y Uso de Servicios
- Inyección de Dependencias
- Inyectores Jerárquicos
Módulo 5: Enrutamiento y Navegación
Módulo 6: Formularios en Angular
- Formularios Basados en Plantillas
- Formularios Reactivos
- Validación de Formularios
- Formularios Dinámicos
Módulo 7: Cliente HTTP y Observables
- Introducción al Cliente HTTP
- Realizando Solicitudes HTTP
- Manejo de Respuestas HTTP
- Uso de Observables
- Manejo de Errores
Módulo 8: Gestión de Estado
- Introducción a la Gestión de Estado
- Uso de Servicios para la Gestión de Estado
- NgRx Store
- NgRx Effects
- NgRx Entity
Módulo 9: Pruebas en Angular
- Pruebas Unitarias
- Pruebas de Componentes
- Pruebas de Servicios
- Pruebas de Extremo a Extremo
- Simulación de Dependencias
Módulo 10: Conceptos Avanzados de Angular
- Angular Universal
- Optimización del Rendimiento
- Internacionalización (i18n)
- Pipes Personalizados
- Animaciones en Angular