Интеграция Validator.js в Angular строится вокруг расширения
стандартной системы валидации форм через ReactiveForms и
Template-driven forms, где библиотека используется как слой
низкоуровневых проверок строковых значений. Основная идея заключается в
том, что Angular отвечает за жизненный цикл и состояние форм, а
Validator.js — за детальную проверку значений.
Библиотека устанавливается стандартным способом через npm:
npm install validator
После установки функции подключаются точечно, чтобы не перегружать бандл:
import isEmail from 'validator/lib/isEmail';
import isURL from 'validator/lib/isURL';
import isLength from 'validator/lib/isLength';
import isAlphanumeric from 'validator/lib/isAlphanumeric';
Такой подход предпочтительнее импорта всей библиотеки целиком, поскольку Angular-приложения чувствительны к размеру итогового bundle.
Reactive Forms используют объект FormControl, который
принимает массив валидаторов:
import { FormControl, Validators } from '@angular/forms';
const emailControl = new FormControl('', [
Validators.required
]);
Validator.js подключается через создание кастомных функций:
import { AbstractControl, ValidationErrors } from '@angular/forms';
import isEmail from 'validator/lib/isEmail';
export function emailValidator(control: AbstractControl): ValidationErrors | null {
const value = control.value;
if (!value) {
return null;
}
return isEmail(value) ? null : { emailInvalid: true };
}
Использование в форме:
const emailControl = new FormControl('', [
Validators.required,
emailValidator
]);
Angular ожидает, что валидатор возвращает либо null,
либо объект ошибок. Validator.js возвращает boolean, поэтому адаптация
заключается в преобразовании результата.
Шаблон универсального валидатора:
export function createValidator(
validatorFn: (value: string) => boolean,
errorKey: string
) {
return (control: AbstractControl): ValidationErrors | null => {
const value = control.value;
if (value === null || value === undefined || value === '') {
return null;
}
return validatorFn(value) ? null : { [errorKey]: true };
};
}
Пример использования:
import isURL from 'validator/lib/isURL';
export const urlValidator = createValidator(isURL, 'invalidUrl');
import isEmail from 'validator/lib/isEmail';
export const emailValidator = createValidator(isEmail, 'emailInvalid');
import isURL from 'validator/lib/isURL';
export const urlValidator = createValidator(
(value) => isURL(value, { require_protocol: true }),
'urlInvalid'
);
import isLength from 'validator/lib/isLength';
export const minLengthValidator = (min: number) =>
createValidator(
(value) => isLength(value, { min }),
'minLengthInvalid'
);
import isAlphanumeric from 'validator/lib/isAlphanumeric';
export const alphanumericValidator =
createValidator(isAlphanumeric, 'notAlphanumeric');
Angular позволяет объединять встроенные и сторонние проверки:
const usernameControl = new FormControl('', [
Validators.required,
Validators.minLength(3),
alphanumericValidator
]);
Такое разделение разгружает логику: Angular выполняет структурные проверки, Validator.js — семантические.
Validator.js чаще всего ожидает строку. Angular же может передавать
null. Поэтому нормализация становится обязательной частью
слоя адаптации:
const value = (control.value ?? '').toString().trim();
Игнорирование этого шага приводит к ложным ошибкам при первичной инициализации формы.
Validator.js можно использовать и в проверках нескольких полей:
import { FormGroup, ValidationErrors } from '@angular/forms';
import isNumeric from 'validator/lib/isNumeric';
export function priceRangeValidator(group: FormGroup): ValidationErrors | null {
const min = group.get('min')?.value;
const max = group.get('max')?.value;
if (!isNumeric(min) || !isNumeric(max)) {
return { notNumeric: true };
}
return Number(min) <= Number(max)
? null
: { rangeInvalid: true };
}
Применение:
const form = new FormGroup(
{
min: new FormControl(''),
max: new FormControl('')
},
{ validators: priceRangeValidator }
);
В шаблонных формах интеграция выполняется через директивы:
import { Directive } from '@angular/core';
import { NG_VALIDATORS, Validator, AbstractControl } from '@angular/forms';
import isEmail from 'validator/lib/isEmail';
@Directive({
selector: '[emailValidator]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: EmailValidatorDirective,
multi: true
}
]
})
export class EmailValidatorDirective implements Validator {
validate(control: AbstractControl) {
const value = control.value;
if (!value) {
return null;
}
return isEmail(value) ? null : { emailInvalid: true };
}
}
Использование в HTML:
<input name="email" ngModel emailValidator />
При масштабировании приложения валидаторы выносятся в отдельный слой:
@Injectable({ providedIn: 'root' })
export class ValidationService {
email = emailValidator;
url = urlValidator;
minLength(min: number) {
return minLengthValidator(min);
}
}
Это упрощает повторное использование и унифицирует правила.
Angular допускает строгую типизацию ошибок:
interface EmailError {
emailInvalid: true;
}
type EmailValidationErrors = EmailError | null;
Это позволяет строить предсказуемую модель обработки ошибок в UI-слое.
При частой валидации (например, ввод в реальном времени) важны следующие ограничения:
validator/lib/...Angular повторно вызывает валидаторы при каждом изменении состояния
FormControl. Это делает критичным отсутствие побочных
эффектов внутри функций валидации. Validator.js в этом контексте
подходит как чистый функциональный слой, поскольку не изменяет входные
данные и не хранит состояние.
Результат валидации формируется в объект:
{ emailInvalid: true }
Доступ к ошибке:
emailControl.errors?.['emailInvalid']
Такой формат позволяет унифицировать отображение сообщений об ошибках независимо от источника проверки.
Validator.js часто применяется как общий слой валидации между фронтендом и Node.js API. Это снижает расхождение правил проверки данных на клиенте и сервере, особенно в случаях email, URL, длины строк и числовых диапазонов.