La validación de formularios es una parte crucial en el desarrollo de aplicaciones web, ya que garantiza que los datos ingresados por los usuarios sean correctos y cumplan con los requisitos esperados. Angular proporciona herramientas poderosas para manejar la validación tanto en formularios basados en plantillas como en formularios reactivos.

Conceptos Clave

  1. Tipos de Validación:

    • Validación Incorporada: Angular ofrece validadores incorporados como required, minlength, maxlength, pattern, etc.
    • Validación Personalizada: Puedes crear tus propios validadores para casos específicos.
  2. Estados de Control:

    • valid: El control cumple con todas las validaciones.
    • invalid: El control no cumple con alguna validación.
    • pristine: El control no ha sido modificado por el usuario.
    • dirty: El control ha sido modificado por el usuario.
    • touched: El control ha sido enfocado y desenfocado.
    • untouched: El control no ha sido enfocado.
  3. Mensajes de Error: Mostrar mensajes de error específicos basados en el estado de validación del control.

Validación en Formularios Basados en Plantillas

Ejemplo Práctico

Vamos a crear un formulario simple con validación utilizando formularios basados en plantillas.

<!-- app.component.html -->
<form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
  <div>
    <label for="name">Nombre:</label>
    <input type="text" id="name" name="name" ngModel required minlength="3" #name="ngModel">
    <div *ngIf="name.invalid && (name.dirty || name.touched)">
      <small *ngIf="name.errors?.required">El nombre es obligatorio.</small>
      <small *ngIf="name.errors?.minlength">El nombre debe tener al menos 3 caracteres.</small>
    </div>
  </div>
  <div>
    <label for="email">Correo Electrónico:</label>
    <input type="email" id="email" name="email" ngModel required email #email="ngModel">
    <div *ngIf="email.invalid && (email.dirty || email.touched)">
      <small *ngIf="email.errors?.required">El correo electrónico es obligatorio.</small>
      <small *ngIf="email.errors?.email">El correo electrónico no es válido.</small>
    </div>
  </div>
  <button type="submit" [disabled]="userForm.invalid">Enviar</button>
</form>
// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  onSubmit(form: any) {
    console.log('Formulario enviado', form);
  }
}

Explicación

  • ngModel: Vincula el control del formulario a una propiedad del modelo.
  • #name="ngModel": Crea una referencia local para acceder al estado del control.
  • required, minlength, email: Validadores incorporados.
  • *ngIf="name.invalid && (name.dirty || name.touched)": Muestra mensajes de error solo si el control es inválido y ha sido modificado o enfocado.

Validación en Formularios Reactivos

Ejemplo Práctico

Vamos a crear un formulario reactivo con validación.

// app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  userForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.userForm = this.fb.group({
      name: ['', [Validators.required, Validators.minLength(3)]],
      email: ['', [Validators.required, Validators.email]]
    });
  }

  get name() {
    return this.userForm.get('name');
  }

  get email() {
    return this.userForm.get('email');
  }

  onSubmit() {
    if (this.userForm.valid) {
      console.log('Formulario enviado', this.userForm.value);
    }
  }
}
<!-- app.component.html -->
<form [formGroup]="userForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="name">Nombre:</label>
    <input type="text" id="name" formControlName="name">
    <div *ngIf="name.invalid && (name.dirty || name.touched)">
      <small *ngIf="name.errors?.required">El nombre es obligatorio.</small>
      <small *ngIf="name.errors?.minlength">El nombre debe tener al menos 3 caracteres.</small>
    </div>
  </div>
  <div>
    <label for="email">Correo Electrónico:</label>
    <input type="email" id="email" formControlName="email">
    <div *ngIf="email.invalid && (email.dirty || email.touched)">
      <small *ngIf="email.errors?.required">El correo electrónico es obligatorio.</small>
      <small *ngIf="email.errors?.email">El correo electrónico no es válido.</small>
    </div>
  </div>
  <button type="submit" [disabled]="userForm.invalid">Enviar</button>
</form>

Explicación

  • FormBuilder: Servicio para crear instancias de FormGroup y FormControl.
  • formControlName: Vincula el control del formulario a una propiedad del modelo reactivo.
  • Validators: Proporciona validadores incorporados como required, minLength, email.
  • get name() y get email(): Métodos para acceder fácilmente a los controles del formulario.

Ejercicio Práctico

Ejercicio

Crea un formulario de registro con los siguientes campos y validaciones:

  • Nombre de Usuario: Obligatorio, mínimo 5 caracteres.
  • Contraseña: Obligatorio, mínimo 8 caracteres.
  • Confirmar Contraseña: Obligatorio, debe coincidir con la contraseña.
  • Correo Electrónico: Obligatorio, debe ser un correo válido.

Solución

// app.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  registerForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.registerForm = this.fb.group({
      username: ['', [Validators.required, Validators.minLength(5)]],
      password: ['', [Validators.required, Validators.minLength(8)]],
      confirmPassword: ['', [Validators.required]],
      email: ['', [Validators.required, Validators.email]]
    }, { validator: this.passwordMatchValidator });
  }

  passwordMatchValidator(form: FormGroup) {
    return form.get('password').value === form.get('confirmPassword').value
      ? null : { mismatch: true };
  }

  get username() {
    return this.registerForm.get('username');
  }

  get password() {
    return this.registerForm.get('password');
  }

  get confirmPassword() {
    return this.registerForm.get('confirmPassword');
  }

  get email() {
    return this.registerForm.get('email');
  }

  onSubmit() {
    if (this.registerForm.valid) {
      console.log('Formulario de registro enviado', this.registerForm.value);
    }
  }
}
<!-- app.component.html -->
<form [formGroup]="registerForm" (ngSubmit)="onSubmit()">
  <div>
    <label for="username">Nombre de Usuario:</label>
    <input type="text" id="username" formControlName="username">
    <div *ngIf="username.invalid && (username.dirty || username.touched)">
      <small *ngIf="username.errors?.required">El nombre de usuario es obligatorio.</small>
      <small *ngIf="username.errors?.minlength">El nombre de usuario debe tener al menos 5 caracteres.</small>
    </div>
  </div>
  <div>
    <label for="password">Contraseña:</label>
    <input type="password" id="password" formControlName="password">
    <div *ngIf="password.invalid && (password.dirty || password.touched)">
      <small *ngIf="password.errors?.required">La contraseña es obligatoria.</small>
      <small *ngIf="password.errors?.minlength">La contraseña debe tener al menos 8 caracteres.</small>
    </div>
  </div>
  <div>
    <label for="confirmPassword">Confirmar Contraseña:</label>
    <input type="password" id="confirmPassword" formControlName="confirmPassword">
    <div *ngIf="confirmPassword.invalid && (confirmPassword.dirty || confirmPassword.touched)">
      <small *ngIf="confirmPassword.errors?.required">Confirmar contraseña es obligatorio.</small>
      <small *ngIf="registerForm.errors?.mismatch">Las contraseñas no coinciden.</small>
    </div>
  </div>
  <div>
    <label for="email">Correo Electrónico:</label>
    <input type="email" id="email" formControlName="email">
    <div *ngIf="email.invalid && (email.dirty || email.touched)">
      <small *ngIf="email.errors?.required">El correo electrónico es obligatorio.</small>
      <small *ngIf="email.errors?.email">El correo electrónico no es válido.</small>
    </div>
  </div>
  <button type="submit" [disabled]="registerForm.invalid">Registrar</button>
</form>

Explicación

  • passwordMatchValidator: Validador personalizado para asegurar que las contraseñas coincidan.
  • registerForm.errors?.mismatch: Muestra un mensaje de error si las contraseñas no coinciden.

Conclusión

La validación de formularios en Angular es una herramienta poderosa que permite asegurar la integridad de los datos ingresados por los usuarios. Ya sea utilizando formularios basados en plantillas o formularios reactivos, Angular proporciona una amplia gama de validadores incorporados y la capacidad de crear validadores personalizados para satisfacer necesidades específicas. Con la práctica y la comprensión de estos conceptos, podrás crear formularios robustos y seguros en tus aplicaciones Angular.

Curso de Angular

Módulo 1: Introducción a Angular

Módulo 2: Componentes de Angular

Módulo 3: Enlace de Datos y Directivas

Módulo 4: Servicios e Inyección de Dependencias

Módulo 5: Enrutamiento y Navegación

Módulo 6: Formularios en Angular

Módulo 7: Cliente HTTP y Observables

Módulo 8: Gestión de Estado

Módulo 9: Pruebas en Angular

Módulo 10: Conceptos Avanzados de Angular

Módulo 11: Despliegue y Mejores Prácticas

© Copyright 2024. Todos los derechos reservados