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

GroupNode

Defined in: core/nodes/group-node.ts:82

GroupNode - узел для группы полей

Поддерживает два API:

  1. Старый API (только schema) - обратная совместимость
  2. Новый API (config с form, behavior, validation) - автоматическое применение схем

Example

// 1. Старый способ (обратная совместимость)
const simpleForm = new GroupNode({
email: { value: '', component: Input },
password: { value: '', component: Input },
});

// 2. Новый способ (с behavior и validation схемами)
const fullForm = new GroupNode({
form: {
email: { value: '', component: Input },
password: { value: '', component: Input },
},
behavior: (path) => {
computeFrom(path.email, [path.email], (values) => values[0]?.trim());
},
validation: (path) => {
required(path.email, { message: 'Email обязателен' });
email(path.email);
required(path.password);
minLength(path.password, 8);
},
});

// Прямой доступ к полям через Proxy
fullForm.email.setValue('test@mail.com');
await fullForm.validate();
console.log(fullForm.valid.value); // true

Extends

Type Parameters

T

T

Accessors

fields

Get Signature

get fields(): FieldRegistry<T>;

Defined in: core/nodes/group-node.ts:427

Получить Map всех полей формы

Используется в FieldPathNavigator для навигации по полям

Returns

FieldRegistry<T>

Map полей формы

Constructors

Constructor

new GroupNode<T>(schema): GroupNode<T>;

Defined in: core/nodes/group-node.ts:180

Создать GroupNode только со схемой формы (обратная совместимость)

Parameters

schema

FormSchema<T>

Returns

GroupNode<T>

Overrides

FormNode.constructor

Constructor

new GroupNode<T>(config): GroupNode<T>;

Defined in: core/nodes/group-node.ts:185

Создать GroupNode с полной конфигурацией (form, behavior, validation)

Parameters

config

GroupNodeConfig<T>

Returns

GroupNode<T>

Overrides

FormNode<T>.constructor

Methods

applyBehaviorSchema()

applyBehaviorSchema(schemaFn): () => void;

Defined in: core/nodes/group-node.ts:604

Применить behavior schema к форме

✅ РЕФАКТОРИНГ: Делегирование BehaviorApplicator (SRP)

Логика применения behavior схемы извлечена в BehaviorApplicator для:

  • Соблюдения Single Responsibility Principle
  • Уменьшения размера GroupNode (~50 строк)
  • Улучшения тестируемости
  • Консистентности с ValidationApplicator

Parameters

schemaFn

BehaviorSchemaFn<T>

Функция описания поведения формы

Returns

Функция cleanup для отписки от всех behaviors

(): void;
Returns

void

Example

import { copyFrom, enableWhen, computeFrom } from '@/lib/forms/core/behaviors';

const behaviorSchema: BehaviorSchemaFn<MyForm> = (path) => {
copyFrom(path.residenceAddress, path.registrationAddress, {
when: (form) => form.sameAsRegistration === true
});

enableWhen(path.propertyValue, (form) => form.loanType === 'mortgage');

computeFrom(
path.initialPayment,
[path.propertyValue],
(propertyValue) => propertyValue ? propertyValue * 0.2 : null
);
};

const cleanup = form.applyBehaviorSchema(behaviorSchema);

// Cleanup при unmount
useEffect(() => cleanup, []);

applyContextualValidators()

applyContextualValidators(validators): Promise<void>;

Defined in: core/nodes/group-node.ts:694

Применить contextual валидаторы к полям

✅ РЕФАКТОРИНГ: Делегирование ValidationApplicator (SRP)

Логика применения валидаторов извлечена в ValidationApplicator для:

  • Соблюдения Single Responsibility Principle
  • Уменьшения размера GroupNode (~120 строк)
  • Улучшения тестируемости

Parameters

validators

ValidatorRegistration[]

Зарегистрированные валидаторы

Returns

Promise<void>


applyValidationSchema()

applyValidationSchema(schemaFn): void;

Defined in: core/nodes/group-node.ts:551

Применить validation schema к форме

Использует локальный реестр валидаторов (this.validationRegistry) вместо глобального Singleton для изоляции форм друг от друга.

Parameters

schemaFn

ValidationSchemaFn<T>

Returns

void


clearErrors()

clearErrors(): void;

Defined in: core/nodes/group-node.ts:392

Очистить все errors (form-level + field-level)

Returns

void

Overrides

FormNode.clearErrors


disable()

disable(): void;

Defined in: core/nodes/form-node.ts:370

Отключить узел

Template Method: обновляет статус в базовом классе, вызывает hook для кастомной логики в наследниках

Отключенные узлы не проходят валидацию и не включаются в getValue()

Returns

void

Inherited from

FormNode.disable


dispose()

dispose(): void;

Defined in: core/nodes/group-node.ts:876

Очистить все ресурсы узла Рекурсивно очищает все subscriptions и дочерние узлы

Returns

void

Example

useEffect(() => {
return () => {
form.dispose();
};
}, []);

Overrides

FormNode.dispose


enable()

enable(): void;

Defined in: core/nodes/form-node.ts:381

Включить узел

Template Method: обновляет статус в базовом классе, вызывает hook для кастомной логики в наследниках

Returns

void

Inherited from

FormNode.enable


getAllFields()

getAllFields(): IterableIterator<FormNode<FormValue>>;

Defined in: core/nodes/group-node.ts:476

Получить все поля формы как итератор

Предоставляет доступ к внутренним полям для валидации и других операций

Returns

IterableIterator<FormNode<FormValue>>

Итератор по всем полям формы

Example

// Валидация всех полей
await Promise.all(
Array.from(form.getAllFields()).map(field => field.validate())
);

getErrors()

getErrors(options?): ValidationError[];

Defined in: core/nodes/form-node.ts:231

Получить ошибки валидации с фильтрацией

Позволяет фильтровать ошибки по различным критериям:

  • По коду ошибки
  • По сообщению (частичное совпадение)
  • По параметрам
  • Через кастомный предикат

Без параметров возвращает все ошибки (эквивалент errors.value)

Parameters

options?

ErrorFilterOptions

Опции фильтрации ошибок

Returns

ValidationError[]

Отфильтрованный массив ошибок валидации

Example

// Все ошибки
const allErrors = form.getErrors();

// Ошибки с конкретным кодом
const requiredErrors = form.getErrors({ code: 'required' });

// Ошибки с несколькими кодами
const errors = form.getErrors({ code: ['required', 'email'] });

// Ошибки по сообщению
const passwordErrors = form.getErrors({ message: 'Password' });

// Ошибки по параметрам
const minLengthErrors = form.getErrors({
params: { minLength: 8 }
});

// Кастомная фильтрация
const customErrors = form.getErrors({
predicate: (err) => err.code.startsWith('custom_')
});

Inherited from

FormNode.getErrors


getField()

getField<K>(key): FormNode<T[K]> | undefined;

Defined in: core/nodes/group-node.ts:416

Получить поле по ключу

Публичный метод для доступа к полю из fieldRegistry

Type Parameters

K

K extends string | number | symbol

Parameters

key

K

Ключ поля

Returns

FormNode<T[K]> | undefined

FormNode или undefined, если поле не найдено

Example

const emailField = form.getField('email');
if (emailField) {
console.log(emailField.value.value);
}

getFieldByPath()

getFieldByPath(path): 
| FormNode<FormValue>
| undefined;

Defined in: core/nodes/group-node.ts:637

Получить вложенное поле по пути

Поддерживаемые форматы путей:

  • Simple: "email" - получить поле верхнего уровня
  • Nested: "address.city" - получить вложенное поле
  • Array index: "items[0]" - получить элемент массива по индексу
  • Combined: "items[0].name" - получить поле элемента массива

Parameters

path

string

Путь к полю

Returns

| FormNode<FormValue> | undefined

FormNode если найдено, undefined если путь не существует

Example

const form = new GroupNode({
email: { value: '', component: Input },
address: {
city: { value: '', component: Input }
},
items: [{ name: { value: '', component: Input } }]
});

form.getFieldByPath('email'); // FieldNode
form.getFieldByPath('address.city'); // FieldNode
form.getFieldByPath('items[0]'); // GroupNode
form.getFieldByPath('items[0].name'); // FieldNode
form.getFieldByPath('invalid.path'); // undefined

getProxy()

getProxy(): any;

Defined in: core/nodes/group-node.ts:457

Получить Proxy-инстанс для прямого доступа к полям

Proxy позволяет обращаться к полям формы напрямую через точечную нотацию:

  • form.email вместо form.fields.get('email')
  • form.address.city вместо form.fields.get('address').fields.get('city')

Используется в:

  • BehaviorApplicator для доступа к полям в behavior functions
  • ValidationApplicator для доступа к форме в tree validators

Returns

any

Proxy-инстанс с типобезопасным доступом к полям или сама форма, если proxy не доступен

Example

const form = new GroupNode({
controls: {
email: new FieldNode({ value: '' }),
name: new FieldNode({ value: '' })
}
});

const proxy = form.getProxy();
console.log(proxy.email.value); // Прямой доступ к полю

getValue()

getValue(): T;

Defined in: core/nodes/group-node.ts:252

Получить значение узла (non-reactive) Использует .peek() для получения значения без создания зависимости

Returns

T

Overrides

FormNode.getValue


linkFields()

linkFields<K1, K2>(
sourceKey,
targetKey,
transform?): () => void;

Defined in: core/nodes/group-node.ts:753

Связывает два поля: при изменении source автоматически обновляется target Поддерживает опциональную трансформацию значения

Type Parameters

K1

K1 extends string | number | symbol

K2

K2 extends string | number | symbol

Parameters

sourceKey

K1

Ключ поля-источника

targetKey

K2

Ключ поля-цели

transform?

(value) => T[K2]

Опциональная функция трансформации значения

Returns

Функция отписки для cleanup

(): void;
Returns

void

Example

// Автоматический расчет минимального взноса от стоимости недвижимости
const dispose = form.linkFields(
'propertyValue',
'initialPayment',
(propertyValue) => propertyValue ? propertyValue * 0.2 : null
);

// При изменении propertyValue → автоматически обновится initialPayment
form.propertyValue.setValue(1000000);
// initialPayment станет 200000

// Cleanup
useEffect(() => dispose, []);

markAsDirty()

markAsDirty(): void;

Defined in: core/nodes/form-node.ts:313

Отметить узел как dirty (значение изменено)

Template Method: обновляет signal в базовом классе, вызывает hook для кастомной логики в наследниках

Returns

void

Inherited from

FormNode.markAsDirty


markAsPristine()

markAsPristine(): void;

Defined in: core/nodes/form-node.ts:324

Отметить узел как pristine (значение не изменено)

Template Method: обновляет signal в базовом классе, вызывает hook для кастомной логики в наследниках

Returns

void

Inherited from

FormNode.markAsPristine


markAsTouched()

markAsTouched(): void;

Defined in: core/nodes/form-node.ts:291

Отметить узел как touched (пользователь взаимодействовал)

Template Method: обновляет signal в базовом классе, вызывает hook для кастомной логики в наследниках

Returns

void

Inherited from

FormNode.markAsTouched


markAsUntouched()

markAsUntouched(): void;

Defined in: core/nodes/form-node.ts:302

Отметить узел как untouched

Template Method: обновляет signal в базовом классе, вызывает hook для кастомной логики в наследниках

Returns

void

Inherited from

FormNode.markAsUntouched


onDisable()

protected onDisable(): void;

Defined in: core/nodes/group-node.ts:840

Hook: вызывается после disable()

Для GroupNode: рекурсивно отключаем все дочерние поля

Returns

void

Overrides

FormNode.onDisable


onEnable()

protected onEnable(): void;

Defined in: core/nodes/group-node.ts:854

Hook: вызывается после enable()

Для GroupNode: рекурсивно включаем все дочерние поля

Returns

void

Overrides

FormNode.onEnable


onMarkAsDirty()

protected onMarkAsDirty(): void;

Defined in: core/nodes/group-node.ts:507

Hook: вызывается после markAsDirty()

Для GroupNode: рекурсивно помечаем все дочерние поля как dirty

Returns

void

Overrides

FormNode.onMarkAsDirty


onMarkAsPristine()

protected onMarkAsPristine(): void;

Defined in: core/nodes/group-node.ts:516

Hook: вызывается после markAsPristine()

Для GroupNode: рекурсивно помечаем все дочерние поля как pristine

Returns

void

Overrides

FormNode.onMarkAsPristine


onMarkAsTouched()

protected onMarkAsTouched(): void;

Defined in: core/nodes/group-node.ts:489

Hook: вызывается после markAsTouched()

Для GroupNode: рекурсивно помечаем все дочерние поля как touched

Returns

void

Overrides

FormNode.onMarkAsTouched


onMarkAsUntouched()

protected onMarkAsUntouched(): void;

Defined in: core/nodes/group-node.ts:498

Hook: вызывается после markAsUntouched()

Для GroupNode: рекурсивно помечаем все дочерние поля как untouched

Returns

void

Overrides

FormNode.onMarkAsUntouched


patchValue()

patchValue(value): void;

Defined in: core/nodes/group-node.ts:272

Частично обновить значение узла Для FieldNode: работает как setValue Для GroupNode: обновляет только указанные поля Для ArrayNode: обновляет только указанные элементы

Parameters

value

Partial<T>

частичное значение для обновления

Returns

void

Overrides

FormNode.patchValue


reset()

reset(value?): void;

Defined in: core/nodes/group-node.ts:304

Сбросить форму к указанным значениям (или к initialValues)

Parameters

value?

T

опциональный объект со значениями для сброса

Returns

void

Remarks

Рекурсивно вызывает reset() для всех полей формы

Example

// Сброс к initialValues
form.reset();

// Сброс к новым значениям
form.reset({ email: 'new@mail.com', password: '' });

Overrides

FormNode.reset


resetToInitial()

resetToInitial(): void;

Defined in: core/nodes/group-node.ts:339

Сбросить форму к исходным значениям (initialValues)

Returns

void

Remarks

Рекурсивно вызывает resetToInitial() для всех полей формы. Более явный способ сброса к начальным значениям по сравнению с reset()

Полезно когда:

  • Пользователь нажал "Cancel" - полная отмена изменений
  • Форма была изменена через reset(newValues), но нужно вернуться к самому началу
  • Явное намерение показать "отмена всех изменений"

Example

const form = new GroupNode({
email: { value: 'initial@mail.com', component: Input },
name: { value: 'John', component: Input }
});

form.email.setValue('changed@mail.com');
form.reset({ email: 'temp@mail.com', name: 'Jane' });
console.log(form.getValue()); // { email: 'temp@mail.com', name: 'Jane' }

form.resetToInitial();
console.log(form.getValue()); // { email: 'initial@mail.com', name: 'John' }

setErrors()

setErrors(errors): void;

Defined in: core/nodes/group-node.ts:385

Установить form-level validation errors Используется для server-side validation или кросс-полевых ошибок

Parameters

errors

ValidationError[]

массив ошибок уровня формы

Returns

void

Example

// Server-side validation после submit
try {
await api.createUser(form.getValue());
} catch (error) {
form.setErrors([
{ code: 'duplicate_email', message: 'Email уже используется' }
]);
}

Overrides

FormNode.setErrors


setValue()

setValue(value, options?): void;

Defined in: core/nodes/group-node.ts:261

Установить значение узла

Parameters

value

T

новое значение

options?

SetValueOptions

опции установки значения

Returns

void

Overrides

FormNode.setValue


submit()

submit<R>(onSubmit): Promise<R | null>;

Defined in: core/nodes/group-node.ts:528

Отправить форму Валидирует форму и вызывает onSubmit если форма валидна

Type Parameters

R

R

Parameters

onSubmit

(values) => R | Promise<R>

Returns

Promise<R | null>


touchAll()

touchAll(): void;

Defined in: core/nodes/form-node.ts:354

Пометить все поля (включая вложенные) как touched Алиас для markAsTouched(), но более явно показывает намерение пометить ВСЕ поля рекурсивно

Полезно для:

  • Показа всех ошибок валидации перед submit
  • Принудительного отображения ошибок при нажатии "Validate All"
  • Отображения невалидных полей в wizard/step form

Returns

void

Example

// Показать все ошибки перед submit
form.touchAll();
const isValid = await form.validate();
if (!isValid) {
// Все ошибки теперь видны пользователю
}

// Или использовать submit() который уже вызывает touchAll
await form.submit(async (values) => {
await api.save(values);
});

Inherited from

FormNode.touchAll


validate()

validate(): Promise<boolean>;

Defined in: core/nodes/group-node.ts:349

Запустить валидацию узла

Returns

Promise<boolean>

Promise<boolean> - true если валидация успешна

Overrides

FormNode.validate


watchField()

watchField<K>(fieldPath, callback): () => void;

Defined in: core/nodes/group-node.ts:811

Подписка на изменения вложенного поля по строковому пути Поддерживает вложенные пути типа "address.city"

Type Parameters

K

K extends string | number | symbol

Parameters

fieldPath

K extends string ? K<K> : string

Строковый путь к полю (например, "address.city")

callback

(value) => void | Promise<void>

Функция, вызываемая при изменении поля

Returns

Функция отписки для cleanup

(): void;
Returns

void

Example

// Подписка на изменение страны для загрузки городов
const dispose = form.watchField(
'registrationAddress.country',
async (countryCode) => {
if (countryCode) {
const cities = await fetchCitiesByCountry(countryCode);
form.registrationAddress.city.updateComponentProps({
options: cities
});
}
}
);

// Cleanup
useEffect(() => dispose, []);

Properties

_dirty

protected _dirty: Signal<boolean>;

Defined in: core/nodes/form-node.ts:56

Значение узла было изменено (dirty) Protected: наследники могут читать/изменять через методы

Inherited from

FormNode._dirty


_status

protected _status: Signal<FieldStatus>;

Defined in: core/nodes/form-node.ts:62

Текущий статус узла Protected: наследники могут читать/изменять через методы

Inherited from

FormNode._status


_touched

protected _touched: Signal<boolean>;

Defined in: core/nodes/form-node.ts:50

Пользователь взаимодействовал с узлом (touched) Protected: наследники могут читать/изменять через методы

Inherited from

FormNode._touched


dirty

readonly dirty: ReadonlySignal<boolean>;

Defined in: core/nodes/group-node.ts:167

Значение узла было изменено (dirty) Computed из _dirty для предоставления readonly интерфейса

Overrides

FormNode.dirty


disabled

readonly disabled: ReadonlySignal<boolean>;

Defined in: core/nodes/form-node.ts:99

Узел отключен (disabled)

Inherited from

FormNode.disabled


enabled

readonly enabled: ReadonlySignal<boolean>;

Defined in: core/nodes/form-node.ts:104

Узел включен (enabled)

Inherited from

FormNode.enabled


errors

readonly errors: ReadonlySignal<ValidationError[]>;

Defined in: core/nodes/group-node.ts:169

Массив ошибок валидации

Overrides

FormNode.errors


id

id: string;

Defined in: core/nodes/group-node.ts:86


invalid

readonly invalid: ReadonlySignal<boolean>;

Defined in: core/nodes/group-node.ts:165

Узел невалиден (есть ошибки валидации)

Overrides

FormNode.invalid


pending

readonly pending: ReadonlySignal<boolean>;

Defined in: core/nodes/group-node.ts:168

Выполняется асинхронная валидация

Overrides

FormNode.pending


pristine

readonly pristine: ReadonlySignal<boolean>;

Defined in: core/nodes/form-node.ts:88

Значение узла не было изменено (pristine)

Inherited from

FormNode.pristine


status

readonly status: ReadonlySignal<FieldStatus>;

Defined in: core/nodes/group-node.ts:170

Текущий статус узла Computed из _status для предоставления readonly интерфейса

Overrides

FormNode.status


submitting

readonly submitting: ReadonlySignal<boolean>;

Defined in: core/nodes/group-node.ts:171


touched

readonly touched: ReadonlySignal<boolean>;

Defined in: core/nodes/group-node.ts:166

Пользователь взаимодействовал с узлом (touched) Computed из _touched для предоставления readonly интерфейса

Overrides

FormNode.touched


untouched

readonly untouched: ReadonlySignal<boolean>;

Defined in: core/nodes/form-node.ts:77

Пользователь не взаимодействовал с узлом (untouched)

Inherited from

FormNode.untouched


valid

readonly valid: ReadonlySignal<boolean>;

Defined in: core/nodes/group-node.ts:164

Узел валиден (все валидаторы прошли успешно)

Overrides

FormNode.valid


value

readonly value: ReadonlySignal<T>;

Defined in: core/nodes/group-node.ts:163

Текущее значение узла

  • Для FieldNode: значение поля
  • Для GroupNode: объект со значениями всех полей
  • Для ArrayNode: массив значений элементов

Overrides

FormNode.value