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

В библиотеке Tom Select процесс сериализации данных тесно связан с тем, как компонент хранит внутреннее состояние и как это состояние синхронизируется с DOM-элементом <select>, формами и внешними API. Под сериализацией в данном контексте понимается преобразование выбранных пользователем значений в формат, пригодный для отправки на сервер, сохранения или дальнейшей обработки: строка, массив, JSON-структура.


Внутренняя модель данных Tom Select

Tom Select оперирует двумя уровнями данных:

  • items — массив выбранных элементов (внутреннее состояние)
  • options — полный набор доступных опций

Каждый элемент item представляет собой объект, где ключевым полем выступает значение valueField (по умолчанию "value"), а отображаемый текст берётся из labelField (по умолчанию "text").

new TomSelect('#select', {
  valueField: 'id',
  labelField: 'title',
  searchField: 'title'
});

При такой конфигурации внутренний элемент будет выглядеть так:

{
  id: 42,
  title: "JavaScript"
}

Именно эти объекты становятся основой для сериализации.


Получение сериализованных значений

Метод getValue()

Основной способ извлечения данных — метод getValue().

const ts = new TomSelect('#select');

const value = ts.getValue();

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

  • single select → строка или число
  • multiple select → массив значений

Пример для multiple:

// ["js", "ts", "node"]
const values = ts.getValue();

Важно: возвращаются именно значения valueField, а не целые объекты.


Получение полного объекта данных

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

const items = ts.items;

items содержит массив объектов из options, соответствующих выбранным значениям.

Пример:

[
  { id: "js", title: "JavaScript" },
  { id: "ts", title: "TypeScript" }
]

Это критично для случаев, когда нужно отправлять не только идентификаторы, но и метаданные.


Сериализация в JSON

На практике часто требуется преобразовать состояние в JSON-структуру для API:

const payload = {
  tags: ts.getValue()
};

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

Если требуется передать не только значения, но и дополнительные поля:

const payload = {
  tags: ts.items
};

Однако такой подход увеличивает объём данных и требует согласования с сервером.


Синхронизация с HTML-формами

Tom Select автоматически синхронизирует выбранные значения с оригинальным <select> элементом.

<select id="select" name="tags" multiple>
  <option value="js">JavaScript</option>
  <option value="ts">TypeScript</option>
</select>

После инициализации:

new TomSelect('#select');

При сабмите формы браузер отправит:

tags=js&tags=ts

Это происходит потому, что Tom Select обновляет состояние DOM <option selected>.


Влияние режима multiple и single на сериализацию

single

{
  value: "js"
}
ts.getValue(); // "js"

multiple

ts.getValue(); // ["js", "ts"]

При проектировании API важно учитывать, что тип данных меняется автоматически.


Сериализация созданных пользователем элементов

Если включён режим создания новых опций:

new TomSelect('#select', {
  create: true
});

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

Такие значения:

  • попадают в items
  • сериализуются как обычные строки (valueField)
  • могут не иметь объекта-описания
ts.getValue(); // ["js", "custom-tag"]

Если требуется различать созданные элементы:

const result = ts.items.map(item => ({
  value: item.value,
  created: item.$isNew || false
}));

Контроль формата сериализации через valueField

Ключевым механизмом является valueField, который определяет, что именно попадёт в getValue():

new TomSelect('#select', {
  valueField: 'slug',
  labelField: 'name'
});

Теперь:

ts.getValue(); // ["javascript", "typescript"]

При этом внутренние объекты остаются богатыми:

{
  slug: "javascript",
  name: "JavaScript",
  category: "language"
}

Кастомная сериализация

В сложных сценариях стандартного getValue() недостаточно. Тогда используется ручное преобразование:

const serialized = ts.items.map(item => ({
  id: item.id,
  text: item.title,
  meta: {
    length: item.title.length
  }
}));

Такой подход применяется при:

  • интеграции с нестандартными API
  • необходимости денормализации данных
  • отправке агрегированных структур

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

Tom Select предоставляет события, которые позволяют синхронизировать данные в реальном времени:

new TomSelect('#select', {
  onChange(value) {
    console.log('Serialized:', value);
  }
});

Значение value уже является результатом getValue().

Для расширенной сериализации:

onChange(value) {
  const payload = {
    raw: value,
    full: this.items
  };
}

Проблема согласованности данных

Сериализация зависит от того, насколько синхронизированы:

  • options
  • items
  • DOM <select>

Если данные загружаются асинхронно:

ts.addOption({ id: 1, title: "JS" });
ts.addItem("1");

важно учитывать порядок:

  • сначала addOption
  • затем addItem

иначе items может содержать ссылки на несуществующие опции.


Сериализация при загрузке данных с сервера

Частый сценарий — восстановление состояния:

fetch('/api/data')
  .then(r => r.json())
  .then(data => {
    ts.setValue(data.tags);
  });

Если сервер возвращает полный объект:

ts.setValue(data.items.map(i => i.id));

Tom Select всегда принимает именно valueField, а не объекты.


Влияние плагинов на сериализацию

Некоторые плагины изменяют поведение данных:

  • create — добавляет новые значения
  • remove_button — не влияет на сериализацию, но меняет items
  • checkbox_options — влияет только на UI

С точки зрения сериализации важно помнить: плагины не меняют getValue(), но могут изменять состав items.


Сериализация в строку

Иногда требуется строковый формат:

const str = ts.getValue().join(',');

Результат:

js,ts,node

Такой формат используется:

  • в URL query string
  • в legacy API
  • при логировании

Обратная десериализация

Сериализация всегда предполагает обратный процесс — восстановление состояния:

const values = "js,ts,node".split(',');

ts.setValue(values);

или из JSON:

ts.setValue(JSON.parse(response.tags));

Итоговая модель данных сериализации

Фактически Tom Select можно свести к трём уровням представления:

  • UI уровень → отображение labelField
  • логический уровеньvalueField
  • объектный уровеньitems

И сериализация всегда выбирает один из них:

  • getValue() → логический уровень
  • items → объектный уровень
  • DOM <select> → HTML-уровень

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