feat(frontend): add reusable form validators
- Create emailValidator with stricter pattern than Angular's built-in - Create nameValidator with configurable minLength, maxLength, allowNumbers - Support for Spanish characters (accents, ñ, ü) - Export validators from shared module - Add JSDoc documentation with usage examples
This commit is contained in:
parent
bde0d53ba3
commit
3d4a8b56ff
|
|
@ -7,3 +7,7 @@ export * from './components/ui/connectivity-overlay/connectivity-overlay.compone
|
|||
// Pipes
|
||||
export * from './pipes/credits.pipe';
|
||||
export * from './pipes/initials.pipe';
|
||||
|
||||
// Validators
|
||||
export * from './validators/email.validator';
|
||||
export * from './validators/name.validator';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
|
||||
|
||||
/**
|
||||
* Email validation pattern that matches standard email format.
|
||||
* More strict than HTML5 default email validation.
|
||||
*/
|
||||
const EMAIL_PATTERN = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||
|
||||
/**
|
||||
* Custom email validator that provides stricter validation than Angular's built-in.
|
||||
* Validates format: local@domain.tld
|
||||
*
|
||||
* @returns ValidatorFn that returns null if valid, or { email: true } if invalid
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* this.form = this.fb.group({
|
||||
* email: ['', [Validators.required, emailValidator()]]
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function emailValidator(): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
if (!control.value) {
|
||||
return null; // Let required validator handle empty values
|
||||
}
|
||||
const isValid = EMAIL_PATTERN.test(control.value);
|
||||
return isValid ? null : { email: true };
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export * from './email.validator';
|
||||
export * from './name.validator';
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
|
||||
|
||||
/**
|
||||
* Name validation options.
|
||||
*/
|
||||
export interface NameValidatorOptions {
|
||||
/** Minimum length required (default: 3) */
|
||||
minLength?: number;
|
||||
/** Maximum length allowed (default: 100) */
|
||||
maxLength?: number;
|
||||
/** Whether to allow numbers (default: false) */
|
||||
allowNumbers?: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_OPTIONS: Required<NameValidatorOptions> = {
|
||||
minLength: 3,
|
||||
maxLength: 100,
|
||||
allowNumbers: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom name validator with configurable options.
|
||||
* Validates that name contains only letters, spaces, and common punctuation.
|
||||
*
|
||||
* @param options - Validation options
|
||||
* @returns ValidatorFn that returns validation errors or null
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* this.form = this.fb.group({
|
||||
* name: ['', [Validators.required, nameValidator({ minLength: 2 })]]
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export function nameValidator(options: NameValidatorOptions = {}): ValidatorFn {
|
||||
const opts = { ...DEFAULT_OPTIONS, ...options };
|
||||
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
if (!control.value) {
|
||||
return null; // Let required validator handle empty values
|
||||
}
|
||||
|
||||
const value = control.value.trim();
|
||||
|
||||
if (value.length < opts.minLength) {
|
||||
return { minlength: { requiredLength: opts.minLength, actualLength: value.length } };
|
||||
}
|
||||
|
||||
if (value.length > opts.maxLength) {
|
||||
return { maxlength: { requiredLength: opts.maxLength, actualLength: value.length } };
|
||||
}
|
||||
|
||||
// Pattern: letters (including accented), spaces, hyphens, apostrophes
|
||||
const pattern = opts.allowNumbers
|
||||
? /^[a-zA-ZáéíóúÁÉÍÓÚñÑüÜ0-9\s'-]+$/
|
||||
: /^[a-zA-ZáéíóúÁÉÍÓÚñÑüÜ\s'-]+$/;
|
||||
|
||||
if (!pattern.test(value)) {
|
||||
return { pattern: true };
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue