Работа с hidden полями

При использовании Tom Select ключевая задача hidden-полей заключается в разделении визуального представления данных и их фактического значения в форме. Сам компонент заменяет стандартный <select> на более гибкий интерфейс, однако итоговая отправка формы должна оставаться совместимой с классической HTML-формой, где сервер получает либо одно значение, либо массив значений.

Hidden-поле выступает в роли канонического источника данных. Визуальный список тегов, выбранных элементов или созданных опций существует исключительно на клиенте, тогда как hidden input хранит сериализованное состояние, которое отправляется через FormData.


Базовая модель синхронизации

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

Основные принципы:

  • UI хранит коллекцию выбранных элементов
  • hidden input отражает текущее состояние выбора
  • любое изменение UI немедленно синхронизируется с hidden input
  • при отправке формы используется именно hidden input

Типичная структура HTML:

<select id="tags" multiple></select>
<input type="hidden" name="tags" id="tags-hidden">

Инициализация:

new TomSelect("#tags", {
  plugins: ["remove_button"],
  onChange: function(value) {
    document.querySelector("#tags-hidden").value = value;
  }
});

Формат значений hidden input

Tom Select по умолчанию передаёт значения в виде строки, разделённой запятыми:

"value1,value2,value3"

Такой формат применяется при multiple: true, если не задана кастомная сериализация.

В однозначных select:

"value1"

Однако скрытое поле может быть адаптировано под любые структуры данных.


Сериализация массива значений

При работе с множественным выбором часто требуется преобразование массива в строку или JSON.

CSV-формат

onChange: function(values) {
  hidden.value = values.join(",");
}

Такой подход сохраняет совместимость с классическими backend-парсерами.

JSON-формат

onChange: function(values) {
  hidden.value = JSON.stringify(values);
}

Используется при сложных структурах данных или при передаче объектов.


Работа с объектами вместо строк

Tom Select поддерживает режим, где значение элемента — объект:

{
  id: 1,
  title: "JavaScript"
}

В этом случае hidden input должен хранить только идентификатор или сериализованную структуру.

Хранение только ID

onChange: function(values) {
  const ids = values.map(item => item.id);
  hidden.value = ids.join(",");
}

Хранение полного объекта

onChange: function(values) {
  hidden.value = JSON.stringify(values);
}

Интеграция с FormData

При отправке формы через FormData hidden input становится ключевым источником данных.

const form = document.querySelector("form");

form.addEventListener("submit", function(e) {
  const data = new FormData(form);
  console.log(data.get("tags"));
});

Важно, что Tom Select не участвует в процессе сериализации формы напрямую. Его роль ограничивается синхронизацией состояния.


Динамическое обновление hidden поля

В сложных интерфейсах состояние может изменяться не только через UI, но и программно:

const select = new TomSelect("#tags");
const hidden = document.querySelector("#tags-hidden");

select.addItem("javascript");

hidden.value = select.getValue().join(",");

При программных изменениях необходимо вручную поддерживать консистентность hidden input.


Обработка удаления значений

Удаление элемента из выбора должно синхронизироваться с hidden input без задержек:

onItemRemove: function(value) {
  const current = this.getValue();
  hidden.value = current.join(",");
}

Важно учитывать, что onItemRemove вызывается после обновления внутреннего состояния компонента.


Разделение UI и данных как архитектурный принцип

Использование hidden input в связке с Tom Select отражает классическую архитектурную модель:

  • UI слой управляет взаимодействием
  • состояние компонента хранит структуру выбора
  • hidden input является контрактом с сервером

Такое разделение позволяет:

  • не привязывать сервер к внутренней логике UI
  • сохранять совместимость с HTML-формами
  • использовать стандартные механизмы отправки данных

Работа с несколькими hidden полями

В сложных формах допускается использование нескольких hidden input для одного Tom Select:

<input type="hidden" name="tags_ids" id="tags-ids">
<input type="hidden" name="tags_titles" id="tags-titles">
onChange: function(values) {
  document.querySelector("#tags-ids").value =
    values.map(v => v.id).join(",");

  document.querySelector("#tags-titles").value =
    values.map(v => v.title).join("|");
}

Такой подход применяется при необходимости оптимизировать серверную обработку без дополнительных запросов к справочникам.


Восстановление состояния из hidden input

Hidden input может выступать источником для инициализации состояния компонента:

const hidden = document.querySelector("#tags-hidden");

new TomSelect("#tags", {
  items: hidden.value.split(",")
});

При JSON-формате:

items: JSON.parse(hidden.value || "[]")

Это особенно важно при серверном рендеринге форм.


Проблемы рассинхронизации

Наиболее частые ошибки возникают при:

  • ручном изменении hidden input без обновления UI
  • асинхронной загрузке опций
  • кастомной сериализации без единых правил

Типичный дефект:

  • UI показывает одно состояние
  • hidden input содержит другое
  • сервер получает некорректные данные

Решение — всегда считать Tom Select источником истины, а hidden input производным состоянием.


Работа с асинхронными данными

При загрузке опций через AJAX hidden input должен обновляться только после завершения установки значений:

const select = new TomSelect("#tags", {
  load: function(query, callback) {
    fetch("/tags?q=" + query)
      .then(res => res.json())
      .then(data => callback(data));
  },

  onChange: function(values) {
    hidden.value = JSON.stringify(values);
  }
});

Особенность заключается в том, что значение может быть установлено до полной загрузки справочника, и hidden input должен учитывать только финальное состояние.


Инварианты корректной синхронизации

Для стабильной работы системы необходимо соблюдение следующих условий:

  • любое изменение UI отражается в hidden input
  • hidden input никогда не изменяется напрямую без обновления UI
  • формат данных фиксирован и одинаков на протяжении всего жизненного цикла формы
  • инициализация всегда идемпотентна при повторной загрузке

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