Перейти к основному содержимому

Watch Behaviors

Реакция на изменения полей с кастомной логикой.

watchField

Выполнение callback при изменении значения поля.

import { watchField } from '@reformer/core/behaviors';

behaviors: (path, ctx) => [
watchField(path.country, (newValue, oldValue) => {
console.log(`Страна изменилась с ${oldValue} на ${newValue}`);
// Загрузить города для новой страны
loadCities(newValue);
}),
];

Пример: Динамические опции

const form = new GroupNode({
form: {
category: { value: '' },
subcategory: { value: '' },
},
behaviors: (path, ctx) => [
watchField(path.category, async (category) => {
// Сбросить подкатегорию
form.controls.subcategory.setValue('');

// Загрузить подкатегории
const options = await fetchSubcategories(category);
setSubcategoryOptions(options);
}),
],
});

Пример: Аналитика

behaviors: (path, ctx) => [
watchField(path.step, (step) => {
analytics.track('form_step_changed', { step });
}),
];

revalidateWhen

Запуск повторной валидации поля при изменении другого поля.

import { revalidateWhen } from '@reformer/core/behaviors';

behaviors: (path, ctx) => [
// Перевалидировать confirmPassword при изменении password
revalidateWhen(path.confirmPassword, [path.password]),
];

Пример: Диапазон дат

import { validate } from '@reformer/core/validators';

const form = new GroupNode({
form: {
startDate: { value: '' },
endDate: { value: '' },
},
validation: (path) => {
validate(path.endDate, (value, ctx) => {
const start = ctx.root.controls.startDate.value;
if (start && value && value < start) {
return { endBeforeStart: true };
}
return null;
});
},
behaviors: (path, ctx) => [
// Перевалидировать endDate при изменении startDate
revalidateWhen(path.endDate, [path.startDate]),
],
});

Пример: Кросс-валидация

behaviors: (path, ctx) => [
// Сложность пароля зависит от username (не может содержать его)
revalidateWhen(path.password, [path.username]),

// Подтверждение пароля должно совпадать с паролем
revalidateWhen(path.confirmPassword, [path.password]),
];

Отслеживание нескольких полей

Отслеживание нескольких полей:

behaviors: (path, ctx) => [
watchField([path.firstName, path.lastName], () => {
// Вызывается при изменении любого из них
updateDisplayName();
}),
];

Debounced Watch

Предотвращение слишком частых обновлений:

behaviors: (path, ctx) => [
watchField(
path.searchQuery,
async (query) => {
const results = await search(query);
setSearchResults(results);
},
{ debounce: 300 }
),
];

Watch с очисткой

Возврат функции очистки:

behaviors: (path, ctx) => [
watchField(path.livePreview, (enabled) => {
if (enabled) {
const interval = setInterval(refreshPreview, 1000);
return () => clearInterval(interval); // Очистка
}
}),
];

Комбинирование Watch с другими Behaviors

behaviors: (path, ctx) => [
// Показать premium поля
enableWhen(path.premiumOptions, () => form.controls.plan.value === 'premium'),

// Отслеживать изменения плана
watchField(path.plan, (plan) => {
analytics.track('plan_selected', { plan });
}),

// Перевалидировать зависимые поля
revalidateWhen(path.features, [path.plan]),
];

Следующие шаги