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
| Validador | Archivo | Clave de error | Nivel | Usado |
|---|---|---|---|---|
notifyBeforeResolveValidator | shared/validators/notifyBeforeResolve.ts | notifyNotBeforeResolve | FormGroup | si (departamentos y settings) |
noSpacesValidator() | shared/validators/noSpacesValidator.ts | noSpacesAllowed | control | no |
MustMatch(a, b) | shared/validators/passwordMatch.ts | mustMatch (en el segundo control) | FormGroup | no |
strongPasswordValidator() | shared/validators/passwordMatch.ts | strongPassword | control | no |
adultValidator() | shared/validators/validatorsAdult.ts | underage | control | no |
phoneNumberValidator() | shared/validators/validatorsPhoneNumber.ts | invalidPhoneNumber | control | no |
validateIpAddress() | core/helpers/global/form-validation-utils.ts | invalidIp | control | no |
duplicateCurrency() | core/helpers/global/form-validation-utils.ts | duplicateCurrency | FormArray | no |
maxSizeFileValidator(mb) | core/helpers/global/form-validation-utils.ts | maxSize | control | no |
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.
- Si
group.get('enabled')?.value === falsedevuelvenull: 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. - Lee
resolveInMinutesynotifyInMinutesconNumber(...). Si alguno no es finito (por ejemploNaNpor un texto no numérico) devuelvenull. - Devuelve
nullsinotifyIn < 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 deFormGroup; no devuelve nada sino que llama asetErrors({ mustMatch: true })osetErrors(null)sobre el segundo control. Si ese control ya tenía otro error distinto demustMatch, 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. ClavestrongPassword.adultValidator(): calcula la edad a partir denew Date(control.value)y devuelve{ underage: true }si es menor de 18; considera mes y día. Con valor vacíonew Date('')es una fecha inválida y la comparación conNaNno marca error.phoneNumberValidator(): quita espacios y exige^\+?[0-9]*$; vacío es válido; claveinvalidPhoneNumber.validateIpAddress(): regex de IPv4 (cuatro octetos 0 a 255). Devuelve{ invalidIp: { value } }; un valor vacío es inválido.duplicateCurrency(): sobre unFormArray, mapeacurrencyIdde cada elemento y devuelve{ duplicateCurrency: true }si hay repetidos. Resto del dominio de apuestas.maxSizeFileValidator(maxSizeInMB): devuelve{ maxSize: true }sicontrol.value.sizesupera el límite (el control debe contener unFile).