Сериализация данных формы

Модель данных и внутреннее представление выбора

В основе сериализации лежит внутренняя модель выбранных значений, которая в Choices.js строится вокруг массива элементов. Каждый элемент выбора представляет собой объект с минимумом обязательных полей: value, label, а также дополнительными метаданными, если они были заданы при инициализации (например, selected, disabled, customProperties).

Для одиночного выбора структура упрощается до одного активного элемента, тогда как при множественном выборе поддерживается массив активных элементов, сохраняемый в порядке добавления, если не задана сортировка.

Сериализация данных формы в данном контексте означает преобразование внутреннего состояния компонента в формат, пригодный для отправки на сервер: строку, массив, JSON-структуру или набор ключ-значение через FormData.


Базовый механизм извлечения значений

Основной способ получения данных из экземпляра компонента связан с методом:

instance.getValue();

Поведение метода зависит от режима:

  • одиночный выбор → возвращается объект или примитивное значение
  • множественный выбор → возвращается массив значений

При этом возможны два уровня извлечения:

  • полные объекты выбранных элементов
  • только значения (value)

Для получения упрощённого представления используется параметр:

instance.getValue(true);

В этом режиме возвращается массив или значение, состоящее исключительно из value, без метаданных.


Форматы сериализации: value против объекта

С точки зрения передачи данных на сервер обычно выделяются два подхода.

1. Value-based сериализация

Используется в большинстве форм:

const data = instance.getValue(true);

Результат:

  • одиночный select → "ru"
  • множественный select → ["ru", "en", "kz"]

Этот формат напрямую совместим с классическими HTML-form сериализациями.


2. Object-based сериализация

Применяется при необходимости сохранить контекст:

const data = instance.getValue();

Результат:

[
  { "value": "ru", "label": "Русский" },
  { "value": "en", "label": "English" }
]

Такой формат используется при API-интеграциях, где важна семантика отображаемых данных, а не только ключи.


Интеграция со стандартной сериализацией формы

При использовании обычной HTML-формы Choices.js сохраняет совместимость через скрытый <input> или оригинальный <select> элемент, в зависимости от режима и конфигурации.

В типичной конфигурации библиотека синхронизирует состояние с DOM:

  • обновляет value скрытого поля
  • поддерживает атрибут multiple
  • отражает выбор в оригинальном элементе формы

Таким образом стандартный механизм:

new FormData(form)

автоматически включает значения, выбранные через компонент.


Поведение при submit и FormData

Сериализация при отправке формы зависит от того, каким образом инициализирован компонент.

Сценарий скрытого input

Если используется скрытый <input>:

<input type="hidden" name="language">

то значение обновляется автоматически:

  • при выборе элемента
  • при удалении элемента
  • при очистке списка

И в момент отправки формы:

const formData = new FormData(form);

в formData.get('language') попадает актуальное значение.


Сценарий кастомного select

Если используется оригинальный <select multiple>:

  • библиотека синхронизирует выбранные <option selected>
  • браузер сам сериализует значения в массив через FormData

Пример:

formData.getAll('language');

возвращает все выбранные значения.


Событийная модель и синхронизация состояния

Сериализация тесно связана с событием изменения состояния:

  • change — изменение выбранных значений
  • addItem — добавление элемента
  • removeItem — удаление элемента

Каждое событие приводит к обновлению внутреннего состояния, которое затем отражается в DOM-структуре.

Пример реакции на изменение:

instance.passedElement.element.addEventListener('change', (event) => {
  const value = instance.getValue(true);
});

В этом сценарии сериализация выполняется на лету и может использоваться для подготовки payload без ожидания submit.


JSON-сериализация для API

В современных приложениях часто используется явная JSON-сериализация:

const payload = {
  languages: instance.getValue(true)
};

fetch('/api/profile', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(payload)
});

При множественном выборе структура становится предсказуемой и легко масштабируется:

{
  "languages": ["ru", "en", "kz"]
}

Кастомная сериализация и преобразование данных

В некоторых сценариях требуется преобразование значений перед отправкой.

Типовые трансформации:

  • нормализация регистра
  • маппинг value → id из внешнего справочника
  • агрегация в строку
  • упаковка в объект с метаданными

Пример преобразования в строку:

const serialized = instance.getValue(true).join(',');

Результат:

ru,en,kz

Работа с асинхронными данными и динамическими списками

При использовании динамической загрузки options сериализация зависит от состояния кэша:

  • выбранные элементы могут отсутствовать в текущем наборе options
  • значение хранится отдельно от визуального списка

Choices.js сохраняет consistency через внутренний store, где value сохраняется даже при удалении отображаемого элемента из списка.

Это влияет на сериализацию:

  • getValue() возвращает сохранённые значения, даже если они не отображаются
  • DOM-синхронизация может быть частичной

Очистка состояния и влияние на сериализацию

Методы очистки напрямую влияют на результат сериализации:

  • clearStore() → полное обнуление состояния
  • removeActiveItems() → удаление выбранных элементов
  • setChoiceByValue() → перезапись текущего состояния

После очистки:

instance.getValue(true); // []

или null в случае одиночного выбора.


Множественный выбор и порядок сериализации

Для multiple режимов важен порядок элементов:

  • порядок добавления сохраняется
  • сортировка может быть отключена или переопределена

Сериализация массива:

["b", "a", "c"]

может отличаться от визуального порядка, если включена сортировка options.


Совместимость с backend-валидацией

С точки зрения серверной обработки сериализованные данные обычно сопоставляются с:

  • enum-типами
  • массивами идентификаторов
  • связями many-to-many

Типовая модель:

{
  "roles": ["admin", "editor"]
}

или:

{
  "role_ids": [1, 3, 5]
}

Choices.js не накладывает ограничений на формат, но обеспечивает стабильное представление значений.


Особенности сериализации при кастомных шаблонах

При использовании кастомных шаблонов отображения (itemSelectText, callbackOnCreateTemplates) визуальная часть может отличаться от данных.

Ключевой принцип:

  • шаблон влияет только на UI
  • сериализация всегда использует value

Таким образом, даже при сложном UI:

{
  value: "ru",
  label: "Русский язык (RU)"
}

в сериализации участвует только "ru" при использовании value-based режима.


Сложные кейсы: комбинированные формы

В формах с несколькими экземплярами компонента сериализация становится композитной:

  • каждый экземпляр управляет собственным state
  • FormData объединяет значения по name
  • JSON-представление требует ручной агрегации

Пример структуры:

const payload = {
  languages: languages.getValue(true),
  countries: countries.getValue(true),
  tags: tags.getValue(true)
};

Такой подход формирует единый сериализованный объект, пригодный для API без дополнительной трансформации на сервере.