Buscamos en el mundo online para de este modo darte la respuesta para tu duda, en caso de dudas deja la duda y respondemos con gusto, porque estamos para servirte.
Solución:
Alex tiene razón. Tienes que usar un ErrorStateMatcher. Tuve que investigar mucho para resolver esto, y no había una sola fuente que me diera la respuesta completa. Tuve que improvisar la información que aprendí de múltiples fuentes para encontrar mi propia solución al problema. Con suerte, el siguiente ejemplo te salvará del dolor de cabeza que experimenté.
La forma
Aquí hay un ejemplo de un formulario que usa elementos de Material angular para una página de registro de usuario.
Como puede ver, estoy usando
, , y
etiquetas de Angular Material. Mi primer pensamiento fue agregar el *ngIf
directiva para controlar cuando el
aparecen secciones, ¡pero esto no tiene ningún efecto! La visibilidad está realmente controlada por la validez (y el estado “tocado”) de la
, y no se proporciona un validador para probar la igualdad con otro campo de formulario en HTML o Angular. Ahí es donde el errorStateMatcher
entran en juego las directivas en los campos de confirmación.
los errorStateMatcher
La directiva está integrada en Angular Material y proporciona la capacidad de usar un método personalizado para determinar la validez de un
formulario de control, y permite el acceso al estado de validez del padre para hacerlo. Para comenzar a comprender cómo podemos usar errorStateMatcher para este caso de uso, primero echemos un vistazo a la clase del componente.
La clase de componente
Aquí hay una clase de Componente angular que configura la validación para el formulario usando FormBuilder.
export class App
userRegistrationForm: FormGroup;
confirmValidParentMatcher = new ConfirmValidParentMatcher();
errors = errorMessages;
constructor(
private formBuilder: FormBuilder
)
this.createForm();
createForm()
this.userRegistrationForm = this.formBuilder.group(
fullName: ['', [
Validators.required,
Validators.minLength(1),
Validators.maxLength(128)
]],
emailGroup: this.formBuilder.group(
email: ['', [
Validators.required,
Validators.email
]],
confirmEmail: ['', Validators.required]
, validator: CustomValidators.childrenEqual),
passwordGroup: this.formBuilder.group(
password: ['', [
Validators.required,
Validators.pattern(regExps.password)
]],
confirmPassword: ['', Validators.required]
, validator: CustomValidators.childrenEqual)
);
register(): void
// API call to register your user
La clase establece un FormBuilder
para el formulario de registro de usuario. Note que hay dos FormGroup
s en la clase, uno para confirmar la dirección de correo electrónico y otro para confirmar la contraseña. Los campos individuales usan funciones de validación apropiadas, pero ambos usan un validador personalizado a nivel de grupo, que verifica para asegurarse de que los campos de cada grupo sean iguales entre sí, y devuelve un error de validación si no lo son.
La combinación del validador personalizado para los grupos y la directiva errorStateMatcher es lo que nos proporciona la funcionalidad completa necesaria para mostrar correctamente los errores de validación para los campos de confirmación. Echemos un vistazo al módulo de validación personalizado para reunirlo todo.
Módulo de validación personalizado
Elegí dividir la funcionalidad de validación personalizada en su propio módulo, para que pueda reutilizarse fácilmente. También elegí poner otras cosas relacionadas con la validación de mi formulario en ese módulo, a saber, expresiones regulares y mensajes de error, por la misma razón. Pensando un poco en el futuro, es probable que también permita que un usuario cambie su dirección de correo electrónico y contraseña en un formulario de actualización de usuario, ¿verdad? Aquí está el código para todo el módulo.
import FormGroup, FormControl, FormGroupDirective, NgForm, ValidatorFn from '@angular/forms';
import ErrorStateMatcher from '@angular/material';
/**
* Custom validator functions for reactive form validation
*/
export class CustomValidators
/**
* Validates that child controls in the form group are equal
*/
static childrenEqual: ValidatorFn = (formGroup: FormGroup) =>
const [firstControlName, ...otherControlNames] = Object.keys(formGroup.controls
/**
* Custom ErrorStateMatcher which returns true (error exists) when the parent form group is invalid and the control has been touched
*/
export class ConfirmValidParentMatcher implements ErrorStateMatcher NgForm
/**
* Collection of reusable RegExps
*/
export const regExps: [key: string]: RegExp =
password: /^(?=.*[0-9])(?=.*[[email protected]#$%^&*])[[email protected]#$%^&*]7,15$/
;
/**
* Collection of reusable error messages
*/
export const errorMessages: [key: string]: string =
fullName: 'Full name must be between 1 and 128 characters',
email: 'Email must be a valid email address ([email protected])',
confirmEmail: 'Email addresses must match',
password: 'Password must be between 7 and 15 characters, and contain at least one number and special character',
confirmPassword: 'Passwords must match'
;
Primero echemos un vistazo a la función de validación personalizada para el grupo, CustomValidators.childrenEqual()
. Como vengo de una experiencia en programación orientada a objetos, elegí hacer de esta función una static método de clase, pero podría convertirlo fácilmente en una función independiente. La función debe ser de tipo ValidatorFn
(o la firma literal apropiada), y tome un solo parámetro de tipo AbstractControl
, o cualquier tipo derivado. Elegí hacerlo FormGroup
, ya que ese es el caso de uso para el que está.
El código de la función itera sobre todos los controles en el FormGroup
y asegura que todos sus valores sean iguales a los del primer control. Si lo hacen, vuelve null
(indica que no hay errores), de lo contrario devuelve un childrenNotEqual
error.
Así que ahora tenemos un estado no válido en el grupo cuando los campos no son iguales, pero aún necesitamos usar ese estado para controlar cuándo mostrar nuestro mensaje de error. Nuestro ErrorStateMatcher, ConfirmValidParentMatcher
, es lo que puede hacer esto por nosotros. La directiva errorStateMatcher requiere que apunte a una instancia de una clase que implemente la clase ErrorStateMatcher proporcionada en Angular Material. Entonces esa es la firma que se usa aquí. ErrorStateMatcher requiere la implementación de un isErrorState
método, con la firma que se muestra en el código. Vuelve true
o false
; true
indica que existe un error, lo que invalida el estado del elemento de entrada.
La única línea de código en este método es bastante simple; vuelve true
(existe un error) si el control principal (nuestro FormGroup) no es válido, pero solo si se ha tocado el campo. Esto se alinea con el comportamiento predeterminado de
, que usaremos para el resto de los campos del formulario.
Para unirlo todo, ahora tenemos un FormGroup con un validador personalizado que devuelve un error cuando nuestros campos no son iguales, y un
que se muestra cuando el grupo no es válido. Para ver esta funcionalidad en acción, aquí hay un plunker en funcionamiento con una implementación del código mencionado.
Además, he publicado esta solución en un blog aquí.
Cómo crear una validación personalizada:
si la propiedad interna ‘isValid’ del componente es false, luego establezca el estado de entrada erróneo y muestre un mensaje.
HTML:
Input not valid.
TS:
isValid = true; changeValitationStatus() this.matcher = new InputErrorStateMatcher(!this.isValid); matcher = new InputErrorStateMatcher(!this.isValid); class InputErrorStateMatcher implements ErrorStateMatcher null, form: FormGroupDirective
Y de esta manera tienes una validación usando solo formControl.