Skip to main content

Validadores de formularios

Hay dos ubicaciones: src/app/shared/validators/ (5 archivos) y src/app/core/helpers/global/form-validation-utils.ts (3 validadores heredados). Solo uno está en uso real: notifyBeforeResolveValidator. Ninguno tiene spec. Para la UI de validación visual ver Directivas.

Resumen​

ValidadorArchivoClave de errorNivelUsado
notifyBeforeResolveValidatorshared/validators/notifyBeforeResolve.tsnotifyNotBeforeResolveFormGroupsi (departamentos y settings)
noSpacesValidator()shared/validators/noSpacesValidator.tsnoSpacesAllowedcontrolno
MustMatch(a, b)shared/validators/passwordMatch.tsmustMatch (en el segundo control)FormGroupno
strongPasswordValidator()shared/validators/passwordMatch.tsstrongPasswordcontrolno
adultValidator()shared/validators/validatorsAdult.tsunderagecontrolno
phoneNumberValidator()shared/validators/validatorsPhoneNumber.tsinvalidPhoneNumbercontrolno
validateIpAddress()core/helpers/global/form-validation-utils.tsinvalidIpcontrolno
duplicateCurrency()core/helpers/global/form-validation-utils.tsduplicateCurrencyFormArrayno
maxSizeFileValidator(mb)core/helpers/global/form-validation-utils.tsmaxSizecontrolno

notifyBeforeResolveValidator​

Validador de grupo (recibe el AbstractControl del grupo). Regla: el aviso previo debe ocurrir antes del cierre; avisar en el mismo minuto (o después) equivale a no avisar.

  1. Si group.get('enabled')?.value === false devuelve null: con la resolución automática apagada los campos de tiempo están deshabilitados y marcar error dejaría el formulario inválido sin ningún campo editable donde corregirlo.
  2. Lee resolveInMinutes y notifyInMinutes con Number(...). Si alguno no es finito (por ejemplo NaN por un texto no numérico) devuelve null.
  3. Devuelve null si notifyIn < resolveIn; si no, { notifyNotBeforeResolve: true }.

Se usa en dos formularios que comparten la regla (la del departamento sobrescribe la del tenant; ver Departamentos y Settings):

// features/settings/components/auto-resolution-panel/auto-resolution-panel.component.ts
{ validators: notifyBeforeResolveValidator },

// features/departments/components/department-modal/department-modal.component.ts
}, { validators: notifyBeforeResolveValidator }),

Ambos componentes exponen un getter notifyBeforeResolveError para marcar is-invalid en los dos campos y mostrar el mensaje, ya que el error vive en el grupo y no en un control.

Gotcha: Number('') es 0, por lo que un campo de resolución vacío cuenta como 0 y hace fallar la regla si notifyInMinutes es 0 o mayor.

Validadores sin uso​

  • noSpacesValidator(): { noSpacesAllowed: true } si el valor contiene cualquier espacio en blanco (/\s/).
  • MustMatch(controlName, matchingControlName): se pasa como validador de FormGroup; no devuelve nada sino que llama a setErrors({ mustMatch: true }) o setErrors(null) sobre el segundo control. Si ese control ya tenía otro error distinto de mustMatch, no hace nada. Es un patrón imperativo de la plantilla original: setErrors(null) también borra errores propios del control.
  • strongPasswordValidator(): vacío es válido. Exige un dígito, una mayúscula, un carácter de !@#$%^&*(),.?":{}|<> y longitud entre 8 y 20. Clave strongPassword.
  • adultValidator(): calcula la edad a partir de new Date(control.value) y devuelve { underage: true } si es menor de 18; considera mes y día. Con valor vacío new Date('') es una fecha inválida y la comparación con NaN no marca error.
  • phoneNumberValidator(): quita espacios y exige ^\+?[0-9]*$; vacío es válido; clave invalidPhoneNumber.
  • validateIpAddress(): regex de IPv4 (cuatro octetos 0 a 255). Devuelve { invalidIp: { value } }; un valor vacío es inválido.
  • duplicateCurrency(): sobre un FormArray, mapea currencyId de cada elemento y devuelve { duplicateCurrency: true } si hay repetidos. Resto del dominio de apuestas.
  • maxSizeFileValidator(maxSizeInMB): devuelve { maxSize: true } si control.value.size supera el límite (el control debe contener un File).