Validaci贸n de forma angular

    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 鈥嬧媏n 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 鈥嬧媏n plantillas

    En formularios basados 鈥嬧媏n 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 鈥嬧媏n 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 鈥嬧媏n 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 鈥嬧媏n 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.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *