Validación de forma angular

V

Introducción

Una de las características más comunes en cualquier aplicación web es proporcionar un formulario a los usuarios para que ingresen algunos datos. Utiliza formularios a diario para iniciar sesión, registrarse, realizar pedidos, etc.

Procesar las entradas del usuario antes de validar puede tener graves consecuencias. Puede terminar almacenando datos no válidos como una fecha incorrecta, correo electrónico, edad, etc. También podría ser un problema de seguridad debido a ataques como Secuencias de comandos entre sitios (XSS).

La forma tradicional de validar formularios HTML es mediante JavaScript o JQuery. Desafortunadamente, este enfoque garantiza un montón de código.

Angular, al ser un marco completo, ha brindado un excelente soporte para validar las entradas de los usuarios y mostrar mensajes de validación. Tiene muchos validadores integrados de uso común que puede aprovechar, o incluso puede escribir sus validadores personalizados.

Formas en Angular

Un formulario angular es un formulario HTML normal con pocas características adicionales. Para cada campo (entrada, radio, selección, etc.) en el formulario, necesitamos un objeto del FormControl clase. los FormControl El objeto proporciona información sobre ese campo. Sus value, si el valor es valid, y si no es valido cuales son las validaciones errorsetc.

También proporciona el estado del campo, como touched, untouched, dirty, pristineetc.

Del mismo modo, un FormGroup es la colección de la FormControl objetos. Cada forma angular tiene al menos una FormGroup. Puede decidir tener varios FormGroups en casos de uso como separar las secciones de manejo de detalles personales y detalles profesionales de un formulario de registro de usuario.

Todas las propiedades de un FormGroup (valid, error, etc.) también está disponible para FormControl. Por ejemplo, el valid propiedad de un FormControl volverá true me caigo FormControl las instancias son válidas.

Entonces, para agregar validación a una forma angular, necesitamos dos cosas:

  • Al menos uno FormGroup objeto para el formulario
  • UN FormControl objeto para cada campo en el formulario

Hay dos formas diferentes de crear estos objetos de control. Podemos proporcionar algunas directivas en la plantilla del formulario y Angular puede crear tales controles bajo el capó para nosotros. Los formularios creados de esta manera se denominan formularios basados ​​en plantillas.

Si tenemos algunos casos de uso especiales y queremos más control sobre el formulario, podemos crear explícitamente tales objetos de control. Los formularios creados de esta manera se denominan formas reactivas.

Formularios basados ​​en plantillas

En formularios basados ​​en plantillas, aplicamos el ngModel directiva para cada campo de la plantilla. Angular crea un FormControl objeto bajo el capó para cada uno de esos campos y asócielo con el campo respectivo:

<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name"
         ngModel name="name">
</div>

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username"
         ngModel name="username">
</div>

Nota: Con ngModel, se requiere proporcionar el name atributo o definir el FormControl como “independiente” en ngModelOptions, de lo contrario Angular arrojará un error.

También en app.module.ts necesitarías agregar FormsModule a la matriz de importaciones:

import { FormsModule } from '@angular/forms';
// ...some other imports

imports: [
    //...some other imports
    FormsModule
]

Validación en formularios basados ​​en plantillas

Angular ha proporcionado algunos validadores incorporados para validar casos de uso comunes. Para utilizar validadores integrados, necesitaría aplicar atributos de validación a cada campo de formulario donde desee alguna validación. Estos atributos de validación son los mismos que los atributos de validación HTML5 normales como required, minlength, maxlength, etc. Bajo el hod, Angular ha proporcionado directivas para hacer coincidir estos atributos con las funciones de validación definidas en el marco Angular.

Siempre que un FormControlCuando cambia el valor, Angular genera una lista de errores de validación al ejecutar la validación. Si la lista está vacía, significa que es un estado válido; de lo contrario, es un estado no válido.

Digamos que queremos ponerle las siguientes validaciones:

  • Como los campos Nombre y Nombre de usuario tienen la required atributo, queremos mostrar un mensaje de validación si este campo se deja vacío.
  • El campo Nombre debe tener un valor cuyo minlegth y maxlength debe tener 2 y 30 caracteres respectivamente.
  • Si el nombre de usuario tiene espacios, muestre un mensaje de nombre de usuario no válido.

Para cada control de formulario en el que queremos agregar validación, necesitamos agregar atributos de validación apropiados y exportar ngModel a una variable de plantilla local:

<input type="text" class="form-control" id="name"
    required maxlength="30" minlength="2"
    ngModel name="name" #name="ngModel">

En el ejemplo anterior, hemos utilizado los siguientes validadores integrados: required, minlengthy maxlength.

Podemos usar la variable de plantilla name en la plantilla para comprobar los estados de validación de los validadores utilizados:

<div *ngIf="name.invalid && (name.dirty || name.touched)"
    class="alert alert-danger">
  <div *ngIf="name.errors.required">
    Name is required.
  </div>
  <div *ngIf="name.errors.minlength">
    Name cannot be more than 30 characters long.
  </div>
  <div *ngIf="name.errors.minlength">
    Name must be at least 2 characters long.
  </div>
</div>

Como hemos usado una declaración condicional para representar la primera div, solo se mostrará si el estado del validador integrado es invalid. Hemos explicado al comienzo de la sección cómo se determina el estado como valid o invalid.

Del mismo modo, el interior div's se mostrará solo si la variable de plantilla name tiene una propiedad errors y el errors La propiedad tiene una de las siguientes propiedades: required, minlength y maxlength y la identificación del valor de la propiedad true. Ya hemos discutido cómo la variable de plantilla se une a la ngModel directiva y recibe estas propiedades cada vez que hay algún cambio en el control de formulario y después de que Angular ejecuta la validación para ese campo.

Nota: Es importante comprobar dirty y touched afirma, de lo contrario, el mensaje de error se mostrará la primera vez que se cargue la página, lo cual es malo para la experiencia del usuario. Necesitamos que el mensaje de validación se muestre en una de las siguientes condiciones:

  • El usuario cambia algún valor, es decir, el campo está sucio (formControlObject.dirty)
  • El usuario usa la pestaña o hace clic para cambiar el enfoque a algún otro elemento, es decir, se tocó el campo (formControlObject.touched)

Si desea consultar una lista completa de los validadores integrados de Angular, puede seguir las API de validadores.

Escribir un validador personalizado

A veces, los validadores integrados pueden no cubrir su caso de uso exacto. En este caso, es posible que deba crear su función de validación personalizada.

Una función de validación implementa la ValidatorFn interfaz, lo que significa que debe tener la firma:

interface ValidatorFn {
    (control: AbstractControl): ValidationErrors | null
}

los ValidationErrors debe ser un objeto que tenga uno o más pares clave-valor:

type ValidationErrors = {
    [key: string]: any;
};

La clave debe ser una cadena y se usa para denotar el tipo de error de validación como invalidEmail, required, etc. El valor puede ser cualquier cosa y se utiliza para proporcionar más información sobre el error de validación.

Para el ejemplo anterior, queremos escribir una función de validación personalizada que valide si no hay espacios en el nombre de usuario.

Si bien técnicamente podemos escribir esta función en cualquier lugar de la aplicación, siempre es una buena práctica poner todas las funciones de validación relacionadas dentro de una clase separada:

import { ValidationErrors, AbstractControl } from '@angular/forms';

export class UserRegistrationFormValidators {
    static usernameShouldBeValid(control: AbstractControl): ValidationErrors | null {
        if ((control.value as string).indexOf(' ') >= 0) {
            return { shouldNotHaveSpaces: true }
        }

        // If there is no validation failure, return null
        return null;
    }
}

Nota: En este ejemplo, hemos devuelto true como el valor de la clave shouldNotHaveSpaces porque no necesitamos proporcionar ningún detalle. En algunos casos, es posible que deba proporcionar detalles, por ejemplo:

return { maxlengthExceeded: {
        maxLength: 20,
        actual: control.value.length
    }
}

A continuación, podemos usar esta función de validación UserRegistrationFormValidators.usernameShouldBeValid Para el username control de formulario en nuestro formulario basado en plantillas:

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username"
         required
         UserRegistrationFormValidators.usernameShouldBeValid
         [(ngModel)]="person.username" name="username">
</div>

Formas reactivas

En formas reactivas, creamos FormControl objetos explícitamente en el componente de esa plantilla. Aquí está el formulario HTML normal sin ningún ngModel directiva o validaciones:

<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name">
</div>

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username">
</div>

Supongamos que queremos convertir nuestro formulario basado en plantillas del ejemplo anterior en un formulario reactivo.

Para esto, primero, necesitamos crear explícitamente FormGroup y FormControls para cada campo en el componente de la plantilla:

form = new FormGroup({
    'name': new FormControl(),
    'username': new FormControl(),
})

Nota: Como se mencionó anteriormente, un formulario puede tener más de una FormGroup. En este caso, podemos tener una estructura anidada:

registrationForm = new FormGroup({
    'personalDetailsForm': new FormGroup({
        'name': new FormControl()
    })
})

Puedes leer más sobre FormGroup en el Documentación angular.

Permítanme devolver su atención a nuestro caso de uso.

A continuación, debemos asociar estos FormControl objetos a los campos en el formulario HTML.

<form [formGroup]="registrationForm">
<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name"
         [formControlName]="name">
</div>

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username"
         [formControlName]="username">
</div>
<form>

Aquí aplicamos el formGroup directiva y la asoció con la FormGroup objeto registrationForm que creamos en el componente. También asociamos el formControlName directiva con el respectivo FormControl objetos name y username.

Nota: Las directivas para construir formas reactivas se definen en ReactiveFormsModule. Entonces, si recibe un error como:

Can't bind to formGroup

… entonces debe verificar si ha importado eso ReactiveFormsModule en tu módulo principal app.module.ts.

Validaciones en formas reactivas

En formas reactivas, no pasamos la ngModel directiva y tampoco utilizamos atributos de validación HTML5. Especificamos validadores al crear los objetos del FormControl en el propio componente.

Aquí está la firma del FormControl clase:

class FormControl extends AbstractControl {
    constructor(formState: any = null, validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[])

    // ...
}

Como podemos ver, el primer parámetro es el estado inicial del control que se puede mantener vacío, es decir ''. El segundo parámetro es ValidatorFn.

Para agregar las funciones de validador integradas para un FormControl podemos pasarlo el apropiado ValidatorFn. Para el siguiente ejemplo, hemos utilizado los siguientes validadores integrados required, minLengthy maxLength -:

registrationForm = new FormGroup({
    'name': new FormControl('Enter your name', [
        Validators.required,
        Validators.minLength(2),
        Validators.maxLength(30)
    ]),
    'username': new FormControl('', Validators.required),
})

Nota: Necesitaría importar Validators en el componente.

Tenga en cuenta también que, a diferencia de los formularios basados ​​en plantillas, no utilizamos los atributos de validación. Usamos los respectivos ValidatorFn me gusta Validators.required, Validators.minLength (2), etc. Su editor de código puede proporcionar autocompletar para todos ValidatorFn en el momento en que escribes Validators seguido de un punto ..

Podemos volver a la plantilla y escribir mensajes de validación:

<form [formGroup]="registrationForm">
<div class="form-group">
  <label for="name">Name</label>
  <input type="text" class="form-control" id="name"
         [formControlName]="name">
  <div *ngIf="registrationForm.get('name').invalid && (registrationForm.get('name').dirty || registrationForm.get('name').touched)"
    class="alert alert-danger">
    <div *ngIf="registrationForm.get('name').errors.required">
       Name is required.
    </div>
    <div *ngIf="registrationForm.get('name').errors.minlength">
       Name cannot be more than 30 characters long.
    </div>
    <div *ngIf="registrationForm.get('name').errors.minlength">
       Name must be at least 2 characters long.
    </div>
  </div>
</div>

<div class="form-group">
  <label for="username">Username</label>
  <input type="text" class="form-control" id="username"
         [formControlName]="username">
</div>
<form>

Validadores personalizados para formularios reactivos

Necesitamos escribir la función de validación personalizada de la misma manera que lo hicimos para la sección de formulario basado en plantillas. Podemos usar la misma función de validación personalizada UserRegistrationFormValidators.usernameShouldBeValid en el componente de la forma reactiva:

registrationForm = new FormGroup({
    'name': new FormControl('Enter your name', [
        Validators.required,
        Validators.minLength(2),
        Validators.maxLength(30)
    ]),
    'username': new FormControl('', [
        Validators.required,
        UserRegistrationFormValidators.usernameShouldBeValid
    ]),
})

Conclusión

En este tutorial, exploramos las dos formas diferentes de manejar las entradas del usuario: formularios basados ​​en plantillas y reactivos. Aprendimos a validar ambos tipos de formularios. Y finalmente, también escribimos nuestra función de validación personalizada y la incluimos con los validadores integrados.

Como podemos ver, Angular tiene un gran soporte para formularios y proporciona algunas características útiles debajo del capó para validar formularios. Proporcionar cada característica con formas angulares está más allá del alcance de este tutorial. Puede leer el Documentación angular para obtener información completa.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad