Кастомные валидаторы
Создание переиспользуемых валидаторов для вашего приложения.
Простой кастомный валидатор
Используйте validate() для инлайн кастомных валидаторов:
import { validate } from '@reformer/core/validators';
validation: (path) => {
// Инлайн кастомный валидатор
validate(path.age, (value) => {
if (value < 18) {
return { mustBeAdult: true };
}
return null;
});
};
// Ошибка: { mustBeAdult: true }
Переиспользуемая фабрика валидаторов
// validators/password.ts
import { ValidatorFn } from '@reformer/core';
export function strongPassword(): ValidatorFn {
return (value: string) => {
const errors: Record<string, boolean> = {};
if (!/[A-Z]/.test(value)) {
errors.noUppercase = true;
}
if (!/[a-z]/.test(value)) {
errors.noLowercase = true;
}
if (!/[0-9]/.test(value)) {
errors.noNumber = true;
}
if (value.length < 8) {
errors.tooShort = true;
}
return Object.keys(errors).length ? errors : null;
};
}
// Использование
validate(path.password, strongPassword());
Валидатор с параметрами
export function range(min: number, max: number): ValidatorFn {
return (value: number) => {
if (value < min || value > max) {
return { range: { min, max, actual: value } };
}
return null;
};
}
// Использование
validate(path.quantity, range(1, 100));
// Ошибка: { range: { min: 1, max: 100, actual: 150 } }
Валидатор с контекстом
Доступ к состоянию формы во время валидации:
import { ContextualValidatorFn } from '@reformer/core';
export function matchField(fieldName: string): ContextualValidatorFn {
return (value, context) => {
const otherValue = context.root.controls[fieldName].value;
if (value !== otherValue) {
return { mismatch: { field: fieldName } };
}
return null;
};
}
// Использование
validate(path.confirmPassword, matchField('password'));
Кросс-валидация полей
Валидация связей между полями:
validation: (path) => {
required(path.startDate);
required(path.endDate);
// Валидация, что дата окончания после даты начала
validate(path.endDate, (value, ctx) => {
const startDate = ctx.form.startDate.value.value;
if (value && startDate && new Date(value) < new Date(startDate)) {
return { endBeforeStart: true };
}
return null;
});
};
Валидация элементов массива
Валидация элементов в динамических массивах:
interface ContactForm {
name: string;
emails: string[];
}
const form = new GroupNode<ContactForm>({
form: {
name: { value: '' },
emails: [{ value: '' }],
},
validation: (path) => {
required(path.name);
// Валидация каждого email в массиве
required(path.emails.$each);
email(path.emails.$each);
},
});
Условная валидация с кастомной логикой
Используйте when() для условных кастомных валидаторов:
import { when } from '@reformer/core/validators';
validation: (path) => {
required(path.country);
// Требовать tax ID только для пользователей из США
when(
() => form.controls.country.value === 'US',
(path) => {
required(path.taxId);
validate(path.taxId, (value) => {
if (!/^\d{9}$/.test(value)) {
return { invalidTaxId: true };
}
return null;
});
}
);
};
Следующие шаги
- Behaviors — реактивная логика форм
- API Reference — полная документация API